commit 3853b253b399b2aa3c63f44762887dfba3aea6e7 Author: J Mattsson Date: Thu Feb 8 14:43:43 2024 +1100 Initial commit of picotts component for ESP-IDF. Relevant PicoTTS source imported from https://github.com/ihuguet/picotts rather than submoduled, in an attempt to keep fetches small. diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..042d392 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,97 @@ +set(PICOTTS_SRCS + picopr.c + picosa.c + picokpr.c + picodata.c + picokfst.c + picodbg.c + picokdt.c + picoctrl.c + picoktab.c + picoacph.c + picokdbg.c + # picorsrc.c ### We use our custom esp_picorsrc.c instead + picoos.c + picospho.c + picotok.c + picosig.c + picocep.c + picofftsg.c + picotrns.c + picosig2.c + picoextapi.c + picopal.c + picokpdf.c + picobase.c + picopam.c + picowa.c + picoklex.c + picoapi.c + picoknow.c +) +list(TRANSFORM PICOTTS_SRCS PREPEND "pico/lib/") + + +idf_component_register( + SRCS + "esp_picotts.c" + "esp_picorsrc.c" + ${PICOTTS_SRCS} + INCLUDE_DIRS "include" + PRIV_INCLUDE_DIRS "pico/lib" + PRIV_REQUIRES "esp_partition" +) + +# Suppress warnings in the library source +set_source_files_properties( + ${PICOTTS_SRCS} + PROPERTIES COMPILE_FLAGS + "-Wno-implicit-fallthrough -Wno-unused-but-set-variable -Wno-unused-function" +) + +# PicoTTS attempts to use exp() trickery which relies on a particular floating +# point representation format, which seemingly does not hold on Xtensa. As +# a workaround, we rename the picoos_quick_exp functin and provide our own +# wrapper back to standard math.h exp() instead. +set_source_files_properties( + "pico/lib/picoos.c" + PROPERTIES COMPILE_OPTIONS "-Dpicoos_quick_exp=picoos_quick_nope" +) + +# Embed the correct language resources under known names +set(PICOTTS_TA_BIN "picotts_ta.bin") +set(PICOTTS_SG_BIN "picotts_sg.bin") +set(PICOTTS_LANG_DIR ${COMPONENT_DIR}/pico/lang) +set(PICOTTS_TA_BIN_PATH ${CMAKE_CURRENT_BINARY_DIR}/${PICOTTS_TA_BIN}) +set(PICOTTS_SG_BIN_PATH ${CMAKE_CURRENT_BINARY_DIR}/${PICOTTS_SG_BIN}) +if(CONFIG_PICOTTS_LANGUAGE_EN_GB) + set(PICOTTS_TA_SRC "en-GB_ta.bin") + set(PICOTTS_SG_SRC "en-GB_kh0_sg.bin") +elseif(CONFIG_PICOTTS_LANGUAGE_EN_US) + set(PICOTTS_TA_SRC "en-US_ta.bin") + set(PICOTTS_SG_SRC "en-US_lh0_sg.bin") +elseif(CONFIG_PICOTTS_LANGUAGE_DE_DE) + set(PICOTTS_TA_SRC "de-DE_ta.bin") + set(PICOTTS_SG_SRC "de-DE_gl0_sg.bin") +elseif(CONFIG_PICOTTS_LANGUAGE_ES_ES) + set(PICOTTS_TA_SRC "es-ES_ta.bin") + set(PICOTTS_SG_SRC "es-ES_zl0_sg.bin") +elseif(CONFIG_PICOTTS_LANGUAGE_FR_FR) + set(PICOTTS_TA_SRC "fr-FR_ta.bin") + set(PICOTTS_SG_SRC "fr-FR_nk0_sg.bin") +elseif(CONFIG_PICOTTS_LANGUAGE_IT_IT) + set(PICOTTS_TA_SRC "it-IT_ta.bin") + set(PICOTTS_SG_SRC "it-IT_cm0_sg.bin") +endif() +add_custom_command(OUTPUT ${PICOTTS_TA_BIN} + COMMAND cp ${PICOTTS_LANG_DIR}/${PICOTTS_TA_SRC} ${PICOTTS_TA_BIN_PATH}) +add_custom_command(OUTPUT ${PICOTTS_SG_BIN} + COMMAND cp ${PICOTTS_LANG_DIR}/${PICOTTS_SG_SRC} ${PICOTTS_SG_BIN_PATH}) +add_custom_target(picotts_ta_bin_gen DEPENDS ${PICOTTS_TA_BIN_PATH}) +add_custom_target(picotts_sg_bin_gen DEPENDS ${PICOTTS_SG_BIN_PATH}) +target_add_binary_data( + ${COMPONENT_LIB} ${PICOTTS_TA_BIN_PATH} BINARY DEPENDS picotts_ta_bin_gen) +target_add_binary_data( + ${COMPONENT_LIB} ${PICOTTS_SG_BIN_PATH} BINARY DEPENDS picotts_sg_bin_gen) +set_property(DIRECTORY "${COMPONENT_DIR}" APPEND PROPERTY + ADDITIONAL_CLEAN_FILES ${PICOTTS_TA_BIN} ${PICOTTS_SG_BIN}) diff --git a/Kconfig b/Kconfig new file mode 100644 index 0000000..186c83a --- /dev/null +++ b/Kconfig @@ -0,0 +1,62 @@ +menu "Pico TTS" + + choice PICOTTS_LANGUAGE + prompt "Voice language" + default PICOTTS_LANGUAGE_EN_GB + + config PICOTTS_LANGUAGE_EN_GB + bool "English (en-GB)" + + config PICOTTS_LANGUAGE_EN_US + bool "English (en-US)" + + config PICOTTS_LANGUAGE_DE_DE + bool "German (de-DE)" + + config PICOTTS_LANGUAGE_ES_ES + bool "Spanish (es-ES)" + + config PICOTTS_LANGUAGE_FR_FR + bool "French (fr-FR)" + + config PICOTTS_LANGUAGE_IT_IT + bool "Italian (it-IT)" + + endchoice + + choice PICOTTS_RESOURCE_MODE + prompt "Resource storage mode" + default PICOTTS_RESOURCE_MODE_EMBED + + config PICOTTS_RESOURCE_MODE_EMBED + bool "Embed into application binary" + + config PICOTTS_RESOURCE_MODE_PARTITION + bool "Load resources from raw partitions" + + endchoice + + config PICOTTS_TA_PARTITION + string "TA resource partition name" if PICOTTS_RESOURCE_MODE_PARTITION + default "picotts_ta" + help + Partition name where the Text Analysis (TA) resource blob is + located. This needs to be flashed separately from the application. + + config PICOTTS_SG_PARTITION + string "SG resource partition name" if PICOTTS_RESOURCE_MODE_PARTITION + default "picotts_sg" + help + Partition name where the Signal Generator (SG) resource blob is + located. This needs to be flashed separately from the application. + + config PICOTTS_INPUT_QUEUE_SIZE + int "TTS input queue size" + default 256 + help + The size of the TTS input quueue used to transfer the text to be + spoken over to the TTS engine. A larger size makes it less likely + that the picotts_add() function will block, but of course has the + downside of using up more memory. + +endmenu diff --git a/README.md b/README.md new file mode 100644 index 0000000..1e4cf53 --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +# PicoTTS + +This component provides an ESP-IDF port of the popular PicoTTS Text-to-Speech engine. While Espressif provides an Chinese language TTS, to date there has been no support for other languages. PicoTTS fills this gap, and provides Text-To-Speech for the following languages: + + - English (UK) + - English (US) + - German + - French + - Italian + - Spanish + +## Requirements + +The Text-to-Speech engine is quite resource intensive. While the code size is only around 175KB, language resources occupy another 750-1400KB of flash depending on language, and the engine uses just over 1.1MB of RAM while initialised. As such an ESP32-S3 with sufficient amount of PSRAM and flash is a recommended target. + +Note that while generating speech, the TTS task may be busy for quite some time and can easily trigger the IDF's watchdog. You may want to adjust the watchdog settings. + +This component does not provide any board-specific audio support. The TTS engine generates 16bit/16KHz samples, and leaves it to the user to direct those to the correct audio device. + +## Getting started + +Using the PicoTTS component is straight forward. Effectively the steps are: + + - Initialise the engine + - Register a callback function to receive the speech samples + - Send text to the engine + - Eventually, shut down the engine + +In code, this can look like: +``` + #include "picotts.h" + + #define TTS_TASK_PRIORITY 5 + #define TTS_CORE 1 + + void my_sample_cb(int16_t *buf, unsigned count) + { + esp_codec_dev_write(speaker_codec_dev, buf, count*2); + } + + if (picotts_init(TTS_TASK_PRIORITY, my_sample_cb, TTS_CORE)) + { + static const msg[] = "Hello, world"; + picotts_add(msg, sizeof(msg)); // Include the \0 to tell TTS to go + + // Do other stuff, or at least wait until the msg has been spoken + + picotts_shutdown(); + } +``` + +API documentation can be found in the [picotts.h](include/picotts.h) header file. + +## Resource handling + +The PicoTTS engine relies on two resource blobs, a Text Analysis (TA) resource and a Signal Generator (SG) resource. In upstream PicoTTS, these are loaded into RAM from files on disk. As RAM is a very precious resource on a microcontroller, this component has replaced the resource loading routines such that they can be accessed directly from memory-mapped flash instead. This reduces the RAM foot-print from 2.5MB down to 1.1MB. + +There are two options on how to bundle the resource files onto flash. The default, and arguably the easiest, is to embed the resource files directly into the application binary. The one downside to this approach is that application size grows significantly, and may present an issue with firmware upgrades. You will definitely use a much larger application partition than usual. Alternatively, the resource files can be placed in dedicated flash partitions and accessed from there instead. These partitions have to be flashed independently from the application partition, but the advantage is that the language resources are no longer directly coupled to the application binary. Which approach is best will depend on the specific project circumstances. + + +### Custom paritions for language resources + +When this component is configured to load its language resources from partitions rather than having them directly embedded into the application binary itself, you will need to add partition entries to hold the Text Analysis (TA) and Signal Generator (SG) resources. Example entries for `partitions.csv`: + +``` +picotts_ta, 0x40, 0x0, , 640K, +picotts_sg, 0x40, 0x1, , 820K, +``` + +You are free to use any valid partition type and subtype. This component loads +purely by the partition name. The partition names may be changed via Kconfig if so desired. + +The partition sizes may be shrunk to better match the language you're using. What's show here are the maximum partition sizes to fit any language bundle. + +### Flashing language resources to partitions + +When configured for loading language resources from partitions, the following commands can be used to flash them to the correct locations. These commands assume the partition names are "picotts\_ta" and "picotts\_sg", respectively. +``` +parttool.py write_partition --partition-name picotts_ta --input build/esp-idf/picotts/picotts_ta.bin +parttool.py write_partition --partition-name picotts_sg --input build/esp-idf/picotts/picotts_sg.bin +``` + +## Examples + +The [boot\_greeting](examples/boot_greeting/README.md) example is written for ESP-BOX and uses this component to issue a greeting upon boot. diff --git a/esp_picorsrc.c b/esp_picorsrc.c new file mode 100644 index 0000000..d9d85b6 --- /dev/null +++ b/esp_picorsrc.c @@ -0,0 +1,180 @@ +/* Copyright (C) 2024 DiUS Computing Pty Ltd. + * Licensed under the Apache 2.0 license. + * + * @author J Mattsson + */ +#include "picoapi.h" +#include "picoapid.h" +#include "picorsrc.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-function" +// We need access to the internal definitions in order to implement an +// alternative resource loader, hence this unorthodox include +#include "pico/lib/picorsrc.c" + +#pragma GCC diagnostic pop + + +static uint16_t esp_pico_load_pi_u16(const char *raw, unsigned offs) +{ + uint16_t a = raw[offs]; + uint16_t b = raw[offs+1]; + return (b << 8 | a); +} + +static uint32_t esp_pico_load_pi_u32(const char *raw, unsigned offs) +{ + uint32_t a = raw[offs]; + uint32_t b = raw[offs+1]; + uint32_t c = raw[offs+2]; + uint32_t d = raw[offs+3]; + return (d << 24 || c << 16 | b << 8 | a); +} + + +pico_status_t verify_svox_header(const char *raw) +{ + const char marker[] = " (C) SVOX AG "; + for (unsigned i = 0; i < sizeof(marker) -1; ++i) + { + if (raw[i] != (marker[i] - 0x20)) + return PICO_EXC_FILE_CORRUPT; + } + return PICO_OK; +} + + +pico_status_t esp_pico_loadResource(pico_System sys, const void *raw, pico_Resource *outResource) +{ + picorsrc_Resource *resource = (picorsrc_Resource *)outResource; + picorsrc_ResourceManager this = sys->rm; + picorsrc_Resource res = picorsrc_newResource(this->common->mm); + if (res == NULL) + return picoos_emRaiseException(this->common->em, PICO_EXC_OUT_OF_MEM, NULL, NULL); + + if (this->numResources >= PICO_MAX_NUM_RESOURCES) + { + picoos_deallocate(this->common->mm, (void *)&res); + return picoos_emRaiseException(this->common->em, PICO_EXC_MAX_NUM_EXCEED, + NULL, (picoos_char *)"no more than %i resources", PICO_MAX_NUM_RESOURCES); + } + + enum { + SVOXHDR_OFFS = 0, // first 13 bytes = " (C) SVOX AG " downshifted by 0x20 + HEADER_LEN_OFFS = 13, // header length read as le u16 after that + DATA_OFFS = HEADER_LEN_OFFS + 2, + }; + pico_status_t status = verify_svox_header(raw + SVOXHDR_OFFS); + if (status != PICO_OK) + return picoos_emRaiseException(this->common->em, PICO_EXC_FILE_CORRUPT, NULL, NULL); + unsigned hdrlen1 = esp_pico_load_pi_u16(raw, HEADER_LEN_OFFS); + + const char *data = (const char *)raw + DATA_OFFS; + + // This effectively covers the readHeader() step in picorsrc_loadResource() + picoos_file_header_t header; + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" + status = picoos_hdrParseHeader(&header, data); + #pragma GCC diagnostic pop + data += hdrlen1; + + if (status == PICO_OK && + isResourceLoaded(this, header.field[PICOOS_HEADER_NAME].value)) + status = PICO_WARN_RESOURCE_DOUBLE_LOAD; + + uint32_t len = 0; + if (status == PICO_OK) + { + len = esp_pico_load_pi_u32(data, 0); + data += 4; + + // We fib things here and /don't/ copy into a PICOOS_ALIGN_SIZE memory area, + // but we get away with it due to the files data areas already being + // align(4), and on the esp that's all we need. + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" + res->raw_mem = data; + #pragma GCC diagnostic pop + res->start = res->raw_mem; + + // Note resource unique name + int n = picoos_strlcpy( + res->name, header.field[PICOOS_HEADER_NAME].value, + PICORSRC_MAX_RSRC_NAME_SIZ); + if (n > PICORSRC_MAX_RSRC_NAME_SIZ) + { + status = PICO_ERR_INDEX_OUT_OF_RANGE; + picoos_emRaiseException( + this->common->em, PICO_ERR_INDEX_OUT_OF_RANGE, NULL, + (picoos_char *)"resource %s", res->name); + } + } + + if (status == PICO_OK) + { + const uint8_t *ctype = header.field[PICOOS_HEADER_CONTENT_TYPE].value; + if (picoos_strcmp(ctype, PICORSRC_FIELD_VALUE_TEXTANA) == 0) + res->type = PICORSRC_TYPE_TEXTANA; + else if (picoos_strcmp(ctype, PICORSRC_FIELD_VALUE_SIGGEN) == 0) + res->type = PICORSRC_TYPE_SIGGEN; + else + res->type = PICORSRC_TYPE_OTHER; + + // Create kb list from resource + status = picorsrc_getKbList(this, res->start, len, &res->kbList); + } + + if (status == PICO_OK) + { + res->next = this->resources; + this->resources = res; + this->numResources++; + *resource = res; + } + else { + picorsrc_disposeResource(this->common->mm, &res); + } + return status; +}; + + +pico_status_t esp_pico_unloadResource(pico_System sys, pico_Resource *inResource) +{ + picorsrc_Resource *resource = (picorsrc_Resource *)inResource; + picorsrc_ResourceManager this = sys->rm; + + picorsrc_Resource r1, r2, rsrc; + + if (resource == NULL) + return PICO_ERR_NULLPTR_ACCESS; + else + rsrc = *resource; + + if (rsrc->lockCount > 0) + return PICO_EXC_RESOURCE_BUSY; + + r1 = NULL; + r2 = this->resources; + while (r2 != NULL && r2 != rsrc) { + r1 = r2; + r2 = r2->next; + } + if (NULL == r1) + this->resources = rsrc->next; + else if (NULL == r2) + return PICO_ERR_OTHER; /* didn't find resource in rm! */ + else + r1->next = rsrc->next; + + if (NULL != rsrc->kbList) + picorsrc_releaseKbList(this, &rsrc->kbList); + + picoos_deallocate(this->common->mm,(void **)resource); + this->numResources--; + + return PICO_OK; +} diff --git a/esp_picorsrc.h b/esp_picorsrc.h new file mode 100644 index 0000000..3db82b8 --- /dev/null +++ b/esp_picorsrc.h @@ -0,0 +1,10 @@ +#ifndef ESP_PICORSRC_H +#define ESP_PICORSRC_H + +#include "picorsrc.h" + +pico_status_t esp_pico_loadResource(pico_System sys, const void *raw, pico_Resource *resource); + +pico_status_t esp_pico_unloadResource(pico_System sys, pico_Resource *inResource); + +#endif diff --git a/esp_picotts.c b/esp_picotts.c new file mode 100644 index 0000000..e3ecfea --- /dev/null +++ b/esp_picotts.c @@ -0,0 +1,344 @@ +/* Copyright (C) 2024 DiUS Computing Pty Ltd. + * Licensed under the Apache 2.0 license. + * + * @author J Mattsson + */ +#include "picotts.h" +#include "picoapi.h" +#include "picoapid.h" +#include "esp_picorsrc.h" +#include "esp_log.h" +#include "esp_partition.h" +#include +#include +#include +#include +#include +#include +#include + +// Yep, that's 1.1MB needed by PicoTTS, not counting the resource files which +// we access directly from flash. +#define PICO_MEM_SIZE 1100000 + +#define PICOTASK_EXIT 0x0000001u + +static picotts_output_fn outputCb; +static picotts_error_notify_fn errorCb; + +static SemaphoreHandle_t exitLock; +static QueueHandle_t textQ; +static TaskHandle_t picoTask; + +static void *picoMemArea; + +static pico_System picoSystem; +static pico_Resource picoTaResource; +static pico_Resource picoSgResource; +static pico_Engine picoEngine; + +static const pico_Char voiceName[] = "PicoVoice"; +static const char tag[] = "picotts"; + + +#ifdef CONFIG_PICOTTS_RESOURCE_MODE_EMBED +// Embedded resources +extern const char ta_bin_start[] asm("_binary_picotts_ta_bin_start"); +extern const char sg_bin_start[] asm("_binary_picotts_sg_bin_start"); + +#else + +static esp_partition_mmap_handle_t taMmap; +static esp_partition_mmap_handle_t sgMmap; + +static const void *find_and_map_partition( + const char *name, esp_partition_mmap_handle_t *handle) +{ + const esp_partition_t *part = + esp_partition_find_first( + ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, name); + if (!part) + { + ESP_LOGE(tag, "Partition '%s' not found", name); + return NULL; + } + else + { + const void *ptr = 0; + esp_err_t ret = esp_partition_mmap( + part, 0, part->size, ESP_PARTITION_MMAP_DATA, &ptr, handle); + ESP_ERROR_CHECK_WITHOUT_ABORT(ret); + ESP_LOGI(tag, "Partition '%s' mmap'd to %p", name, ptr); + return (ret == ESP_OK) ? ptr : NULL; + } +} + +static void unmap_partitions(void) +{ + if (taMmap) + { + esp_partition_munmap(taMmap); + taMmap = 0; + } + if (sgMmap) + { + esp_partition_munmap(sgMmap); + sgMmap = 0; + } +} +#endif + + +static const void *find_ta_bin_start() +{ +#ifdef CONFIG_PICOTTS_RESOURCE_MODE_EMBED + return ta_bin_start; +#else + return find_and_map_partition(CONFIG_PICOTTS_TA_PARTITION, &taMmap); +#endif +} + + +static const void *find_sg_bin_start() +{ +#ifdef CONFIG_PICOTTS_RESOURCE_MODE_EMBED + return sg_bin_start; +#else + return find_and_map_partition(CONFIG_PICOTTS_SG_PARTITION, &sgMmap); +#endif +} + + +// Use regular exp() function as the picotty hack doesn't work on Xtensa +picoos_double picoos_quick_exp(const picoos_double y) +{ + return exp(y); +} + + +static void esp_pico_err_print(const char *what, int code) +{ + pico_Retstring msg; + pico_getSystemStatusMessage(picoSystem, code, msg); + ESP_LOGE(tag, "%s (%i): %s", what, code, msg); +} + + +static void esp_pico_run(void *) +{ + ESP_LOGI(tag, "Task started"); + bool error = false; + while(!error) + { + uint32_t flags; + if (xTaskNotifyWait(0, ~0, &flags, 0) == pdPASS) + { + if (flags & PICOTASK_EXIT) + break; + } + + uint8_t c; + if (xQueuePeek(textQ, &c, pdMS_TO_TICKS(100) == pdPASS)) + { + int16_t processed = 0; + int ret = pico_putTextUtf8(picoEngine, &c, 1, &processed); + if (ret) + { + esp_pico_err_print("Put text failed, stopping TTS", ret); + error = true; + break; + } + else + { + if (processed) + xQueueReceive(textQ, &c, 0); + } + } + + int status; + do { + // Only PICO_DATA_PCM_16BIT is defined, so we don't propage the type info + int16_t outbuf[128]; + int16_t bytes = 0, type = 0; + status = pico_getData(picoEngine, outbuf, sizeof(outbuf), &bytes, &type); + if (bytes > 0) + outputCb(outbuf, bytes/2); + } while (status == PICO_STEP_BUSY); + if (status != PICO_STEP_IDLE) + { + esp_pico_err_print("Get data failed, stopping TTS", status); + error = true; + } + } + ESP_LOGI(tag, "Exiting task"); + xSemaphoreGive(exitLock); + vTaskDelete(NULL); + + if (error && errorCb) + errorCb(); +} + + +static void esp_pico_cleanup(void) +{ + if (picoTask) + { + xTaskNotify(picoTask, PICOTASK_EXIT, eSetBits); + xSemaphoreTake(exitLock, portMAX_DELAY); + picoTask = NULL; + } + + if (picoEngine) + { + pico_disposeEngine(picoSystem, &picoEngine); + pico_releaseVoiceDefinition(picoSystem, voiceName); + picoEngine = NULL; + } + + if (picoSgResource) + { + esp_pico_unloadResource(picoSystem, &picoSgResource); + picoSgResource = NULL; + } + + if (picoTaResource) + { + esp_pico_unloadResource(picoSystem, &picoTaResource); + picoTaResource = NULL; + } + + if (picoSystem) + { + pico_terminate(&picoSystem); + picoSystem = NULL; + } + + free(picoMemArea); + picoMemArea = NULL; + + if (textQ) + { + vQueueDelete(textQ); + textQ = NULL; + } +} + + +bool picotts_init(unsigned prio, picotts_output_fn cb, int core) +{ + if (!exitLock) + exitLock = xSemaphoreCreateBinary(); + + outputCb = cb; + + if (picoMemArea) + { + ESP_LOGE(tag, "already initialized"); + return false; + } + picoMemArea = malloc(PICO_MEM_SIZE); + if (!picoMemArea) + { + ESP_LOGE(tag, "insufficient memory to initialize picotts"); + return false; + } + + #define PICO_INIT_CHECK(msg) \ + if (ret != 0) \ + { \ + esp_pico_err_print(msg, ret); \ + esp_pico_cleanup(); \ + return false; \ + } + + int ret = pico_initialize(picoMemArea, PICO_MEM_SIZE, &picoSystem); + PICO_INIT_CHECK("init failed"); + + const void *ta = find_ta_bin_start(); + if (!ta) + { + ESP_LOGE(tag, "Unable to find text analysis resource"); + return false; + } + else + ESP_LOGI(tag, "Loading text analysis resource from %p", ta); + + ret = esp_pico_loadResource(picoSystem, ta, &picoTaResource); + PICO_INIT_CHECK("Text analysis load failed"); + + const void *sg = find_sg_bin_start(); + if (!sg) + { + ESP_LOGE(tag, "Unable to find signal generator resource"); + return false; + } + else + ESP_LOGI(tag, "Loading signal generator resource from %p", sg); + + ret = esp_pico_loadResource(picoSystem, sg, &picoSgResource); + PICO_INIT_CHECK("Signal generator load failed"); + + ret = pico_createVoiceDefinition(picoSystem, voiceName); + PICO_INIT_CHECK("Voice creation failed"); + + pico_Retstring str; + + ret = pico_getResourceName(picoSystem, picoTaResource, str); + PICO_INIT_CHECK("TA resource name error"); + ret = pico_addResourceToVoiceDefinition( + picoSystem, voiceName, (const pico_Char *)str); + PICO_INIT_CHECK("TA resource add failed"); + + ret = pico_getResourceName(picoSystem, picoSgResource, str); + PICO_INIT_CHECK("SG resource name error"); + ret = pico_addResourceToVoiceDefinition( + picoSystem, voiceName, (const pico_Char *)str); + PICO_INIT_CHECK("SG resource add failed"); + + ret = pico_newEngine(picoSystem, voiceName, &picoEngine); + PICO_INIT_CHECK("Engine creation failed"); + + #undef PICO_INIT_CHECK + + textQ = xQueueCreate(CONFIG_PICOTTS_INPUT_QUEUE_SIZE, sizeof(char)); + if (!textQ) + { + ESP_LOGE(tag, "Failed to create input queue"); + esp_pico_cleanup(); + return false; + } + + if (xTaskCreatePinnedToCore(esp_pico_run, "picotts", 8192, NULL, + prio, &picoTask, core == -1 ? tskNO_AFFINITY : core) + != pdPASS) + { + ESP_LOGE(tag, "Failed to create task"); + esp_pico_cleanup(); + return false; + } + + return true; +} + + +void picotts_add(const char *text, unsigned len) +{ + while(len--) + xQueueSendToBack(textQ, text++, portMAX_DELAY); +} + + +void picotts_shutdown(void) +{ + esp_pico_cleanup(); + +#if CONFIG_PICOTTS_RESOURCE_MODE_PARTITION + unmap_partitions(); +#endif +} + + +void picotts_set_error_notify(picotts_error_notify_fn cb) +{ + errorCb = cb; +} diff --git a/examples/boot_greeting/.gitignore b/examples/boot_greeting/.gitignore new file mode 100644 index 0000000..ff78b72 --- /dev/null +++ b/examples/boot_greeting/.gitignore @@ -0,0 +1,5 @@ +build +sdkconfig +sdkconfig.old +dependencies.lock +managed_components diff --git a/examples/boot_greeting/CMakeLists.txt b/examples/boot_greeting/CMakeLists.txt new file mode 100644 index 0000000..05ec5ba --- /dev/null +++ b/examples/boot_greeting/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.16) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(boot_greeting) diff --git a/examples/boot_greeting/README.md b/examples/boot_greeting/README.md new file mode 100644 index 0000000..5650e84 --- /dev/null +++ b/examples/boot_greeting/README.md @@ -0,0 +1,29 @@ +# PicoTTS Boot Greeting Example + +This example is for ESP-BOX, and demonstrates how to initialise and use the PicoTTS component. + +When booting, the ESP-BOX will issue a spoken greeting. + +The example uses a minimal Board Support Package (BSP) derived from the official Espressif [esp-bsp repo](https://github.com/espressif/esp-bsp/tree/master/bsp/esp-box). Porting the example to other boards is hopefully pretty easy. + +## Configuration + +The greeting message can be customised via Kconfig, as can the volume. + +## Building and flashing + +The default picotts component configuration is to embed the language resource files into the binary, so to build and flash you only need to: + +``` +idf.py build +idf.py flash +``` + +The partition table in this example also makes allowance for having the picotts language resource files stored in separate partitions, but if switching to that option you will additionally need to run: + +``` +parttool.py write_partition --partition-name picotts_ta --input build/esp-idf/picotts/picotts_ta.bin +parttool.py write_partition --partition-name picotts_sg --input build/esp-idf/picotts/picotts_sg.bin +``` + +As usual, the console log can be accessed with `idf.py monitor`. diff --git a/examples/boot_greeting/main/CMakeLists.txt b/examples/boot_greeting/main/CMakeLists.txt new file mode 100644 index 0000000..9311faa --- /dev/null +++ b/examples/boot_greeting/main/CMakeLists.txt @@ -0,0 +1,6 @@ +idf_component_register( + SRCS + "boot_greeting.c" + "bsp/esp-box.c" + INCLUDE_DIRS "" +) diff --git a/examples/boot_greeting/main/Kconfig b/examples/boot_greeting/main/Kconfig new file mode 100644 index 0000000..728be06 --- /dev/null +++ b/examples/boot_greeting/main/Kconfig @@ -0,0 +1,48 @@ +menu "Board Support Package(ESP-BOX)" + + config BSP_ERROR_CHECK + bool "Enable error check in BSP" + default y + help + Error check assert the application before returning the error code. + + menu "I2C" + config BSP_I2C_NUM + int "I2C peripheral index" + default 1 + range 0 1 + help + ESP32S3 has two I2C peripherals, pick the one you want to use. + + config BSP_I2C_FAST_MODE + bool "Enable I2C fast mode" + default y + help + I2C has two speed modes: normal (100kHz) and fast (400kHz). + + config BSP_I2C_CLK_SPEED_HZ + int + default 400000 if BSP_I2C_FAST_MODE + default 100000 + endmenu + + config BSP_I2S_NUM + int "I2S peripheral index" + default 1 + range 0 1 + help + ESP32S3 has two I2S peripherals, pick the one you want to use. +endmenu + +menu "Boot greeting" + + config BOOT_GREETING_MSG + string "Message to speak on startup" + default "ESP now online" + + config BOOT_GREETING_VOLUME + int "Speaker volume (%)" + default 50 + range 0 100 + +endmenu diff --git a/examples/boot_greeting/main/boot_greeting.c b/examples/boot_greeting/main/boot_greeting.c new file mode 100644 index 0000000..d1387e4 --- /dev/null +++ b/examples/boot_greeting/main/boot_greeting.c @@ -0,0 +1,48 @@ +#include "picotts.h" +#include "bsp/esp-bsp.h" +#include +#include +#include + +#define TTS_CORE 1 + +const char greeting[] = CONFIG_BOOT_GREETING_MSG; + +static esp_codec_dev_handle_t spk_codec; + +static void on_samples(int16_t *buf, unsigned count) +{ + esp_codec_dev_write(spk_codec, buf, count*2); +} + + +void app_main() +{ + ESP_ERROR_CHECK(bsp_i2c_init()); + + ESP_ERROR_CHECK(bsp_audio_init(NULL)); + + spk_codec = bsp_audio_codec_speaker_init(); + assert(spk_codec); + esp_codec_dev_set_out_vol(spk_codec, CONFIG_BOOT_GREETING_VOLUME); + esp_codec_dev_sample_info_t fs = { + .sample_rate = PICOTTS_SAMPLE_FREQ_HZ, + .channel = 1, + .bits_per_sample = PICOTTS_SAMPLE_BITS, + }; + esp_codec_dev_open(spk_codec, &fs); + + unsigned prio = uxTaskPriorityGet(NULL); + if (picotts_init(prio, on_samples, TTS_CORE)) + { + picotts_add(greeting, sizeof(greeting)); + + vTaskDelay(pdMS_TO_TICKS(10000)); + + picotts_shutdown(); + } + else + printf("Failed to initialise TTS\n"); + + esp_codec_dev_close(spk_codec); +} diff --git a/examples/boot_greeting/main/bsp/bsp_err_check.h b/examples/boot_greeting/main/bsp/bsp_err_check.h new file mode 100644 index 0000000..01e68e3 --- /dev/null +++ b/examples/boot_greeting/main/bsp/bsp_err_check.h @@ -0,0 +1,59 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_check.h" +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Assert on error, if selected in menuconfig. Otherwise return error code. */ +#if CONFIG_BSP_ERROR_CHECK +#define BSP_ERROR_CHECK_RETURN_ERR(x) ESP_ERROR_CHECK(x) +#define BSP_ERROR_CHECK_RETURN_NULL(x) ESP_ERROR_CHECK(x) +#define BSP_ERROR_CHECK(x, ret) ESP_ERROR_CHECK(x) +#define BSP_NULL_CHECK(x, ret) assert(x) +#define BSP_NULL_CHECK_GOTO(x, goto_tag) assert(x) +#else +#define BSP_ERROR_CHECK_RETURN_ERR(x) do { \ + esp_err_t err_rc_ = (x); \ + if (unlikely(err_rc_ != ESP_OK)) { \ + return err_rc_; \ + } \ + } while(0) + +#define BSP_ERROR_CHECK_RETURN_NULL(x) do { \ + if (unlikely((x) != ESP_OK)) { \ + return NULL; \ + } \ + } while(0) + +#define BSP_NULL_CHECK(x, ret) do { \ + if ((x) == NULL) { \ + return ret; \ + } \ + } while(0) + +#define BSP_ERROR_CHECK(x, ret) do { \ + if (unlikely((x) != ESP_OK)) { \ + return ret; \ + } \ + } while(0) + +#define BSP_NULL_CHECK_GOTO(x, goto_tag) do { \ + if ((x) == NULL) { \ + goto goto_tag; \ + } \ + } while(0) +#endif + +#ifdef __cplusplus +} +#endif + diff --git a/examples/boot_greeting/main/bsp/esp-box.c b/examples/boot_greeting/main/bsp/esp-box.c new file mode 100644 index 0000000..0836ee2 --- /dev/null +++ b/examples/boot_greeting/main/bsp/esp-box.c @@ -0,0 +1,175 @@ +/* + * Cut-down BSP file from original from Espressif's esp-bsp repo. + * + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "esp-box.h" +#include "esp_err.h" +#include "bsp_err_check.h" +#include "esp_codec_dev_defaults.h" + +static const char *TAG = "ESP-BOX"; + +static bool i2c_initialized = false; +static i2s_chan_handle_t i2s_tx_chan = NULL; +static i2s_chan_handle_t i2s_rx_chan = NULL; +static const audio_codec_data_if_t *i2s_data_if = NULL; + + + +/* Can be used for i2s_std_gpio_config_t and/or i2s_std_config_t initialization */ +#define BSP_I2S_GPIO_CFG \ + { \ + .mclk = BSP_I2S_MCLK, \ + .bclk = BSP_I2S_SCLK, \ + .ws = BSP_I2S_LCLK, \ + .dout = BSP_I2S_DOUT, \ + .din = BSP_I2S_DSIN, \ + .invert_flags = { \ + .mclk_inv = false, \ + .bclk_inv = false, \ + .ws_inv = false, \ + }, \ + } + +/* This configuration is used by default in bsp_audio_init() */ +#define BSP_I2S_DUPLEX_MONO_CFG(_sample_rate) \ + { \ + .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(_sample_rate), \ + .slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO), \ + .gpio_cfg = BSP_I2S_GPIO_CFG, \ + } + + +esp_err_t bsp_audio_init(const i2s_std_config_t *i2s_config) +{ + esp_err_t ret = ESP_FAIL; + if (i2s_tx_chan && i2s_rx_chan) { + /* Audio was initialized before */ + return ESP_OK; + } + + /* Setup I2S peripheral */ + i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(CONFIG_BSP_I2S_NUM, I2S_ROLE_MASTER); + chan_cfg.auto_clear = true; // Auto clear the legacy data in the DMA buffer + BSP_ERROR_CHECK_RETURN_ERR(i2s_new_channel(&chan_cfg, &i2s_tx_chan, &i2s_rx_chan)); + + /* Setup I2S channels */ + const i2s_std_config_t std_cfg_default = BSP_I2S_DUPLEX_MONO_CFG(22050); + const i2s_std_config_t *p_i2s_cfg = &std_cfg_default; + if (i2s_config != NULL) { + p_i2s_cfg = i2s_config; + } + + if (i2s_tx_chan != NULL) { + ESP_GOTO_ON_ERROR(i2s_channel_init_std_mode(i2s_tx_chan, p_i2s_cfg), err, TAG, "I2S channel initialization failed"); + ESP_GOTO_ON_ERROR(i2s_channel_enable(i2s_tx_chan), err, TAG, "I2S enabling failed"); + } + if (i2s_rx_chan != NULL) { + ESP_GOTO_ON_ERROR(i2s_channel_init_std_mode(i2s_rx_chan, p_i2s_cfg), err, TAG, "I2S channel initialization failed"); + ESP_GOTO_ON_ERROR(i2s_channel_enable(i2s_rx_chan), err, TAG, "I2S enabling failed"); + } + + audio_codec_i2s_cfg_t i2s_cfg = { + .port = CONFIG_BSP_I2S_NUM, + .rx_handle = i2s_rx_chan, + .tx_handle = i2s_tx_chan, + }; + i2s_data_if = audio_codec_new_i2s_data(&i2s_cfg); + BSP_NULL_CHECK_GOTO(i2s_data_if, err); + + return ESP_OK; + +err: + if (i2s_tx_chan) { + i2s_del_channel(i2s_tx_chan); + } + if (i2s_rx_chan) { + i2s_del_channel(i2s_rx_chan); + } + + return ret; +} + + +const audio_codec_data_if_t *bsp_audio_get_codec_itf(void) +{ + return i2s_data_if; +} + +esp_err_t bsp_i2c_init(void) +{ + /* I2C was initialized before */ + if (i2c_initialized) { + return ESP_OK; + } + + const i2c_config_t i2c_conf = { + .mode = I2C_MODE_MASTER, + .sda_io_num = BSP_I2C_SDA, + .sda_pullup_en = GPIO_PULLUP_DISABLE, + .scl_io_num = BSP_I2C_SCL, + .scl_pullup_en = GPIO_PULLUP_DISABLE, + .master.clk_speed = CONFIG_BSP_I2C_CLK_SPEED_HZ + }; + BSP_ERROR_CHECK_RETURN_ERR(i2c_param_config(BSP_I2C_NUM, &i2c_conf)); + BSP_ERROR_CHECK_RETURN_ERR(i2c_driver_install(BSP_I2C_NUM, i2c_conf.mode, 0, 0, 0)); + + i2c_initialized = true; + + return ESP_OK; +} + + +esp_codec_dev_handle_t bsp_audio_codec_speaker_init(void) +{ + const audio_codec_data_if_t *i2s_data_if = bsp_audio_get_codec_itf(); + if (i2s_data_if == NULL) { + /* Initilize I2C */ + BSP_ERROR_CHECK_RETURN_NULL(bsp_i2c_init()); + /* Configure I2S peripheral and Power Amplifier */ + BSP_ERROR_CHECK_RETURN_NULL(bsp_audio_init(NULL)); + i2s_data_if = bsp_audio_get_codec_itf(); + } + assert(i2s_data_if); + + const audio_codec_gpio_if_t *gpio_if = audio_codec_new_gpio(); + + audio_codec_i2c_cfg_t i2c_cfg = { + .port = BSP_I2C_NUM, + .addr = ES8311_CODEC_DEFAULT_ADDR, + }; + const audio_codec_ctrl_if_t *i2c_ctrl_if = audio_codec_new_i2c_ctrl(&i2c_cfg); + BSP_NULL_CHECK(i2c_ctrl_if, NULL); + + esp_codec_dev_hw_gain_t gain = { + .pa_voltage = 5.0, + .codec_dac_voltage = 3.3, + }; + + es8311_codec_cfg_t es8311_cfg = { + .ctrl_if = i2c_ctrl_if, + .gpio_if = gpio_if, + .codec_mode = ESP_CODEC_DEV_WORK_MODE_DAC, + .pa_pin = BSP_POWER_AMP_IO, + .pa_reverted = false, + .master_mode = false, + .use_mclk = true, + .digital_mic = false, + .invert_mclk = false, + .invert_sclk = false, + .hw_gain = gain, + }; + const audio_codec_if_t *es8311_dev = es8311_codec_new(&es8311_cfg); + BSP_NULL_CHECK(es8311_dev, NULL); + + esp_codec_dev_cfg_t codec_dev_cfg = { + .dev_type = ESP_CODEC_DEV_TYPE_OUT, + .codec_if = es8311_dev, + .data_if = i2s_data_if, + }; + return esp_codec_dev_new(&codec_dev_cfg); +} + diff --git a/examples/boot_greeting/main/bsp/esp-box.h b/examples/boot_greeting/main/bsp/esp-box.h new file mode 100644 index 0000000..203745f --- /dev/null +++ b/examples/boot_greeting/main/bsp/esp-box.h @@ -0,0 +1,27 @@ +#ifndef ESP_BOX_H +#define ESP_BOX_H + +#include "sdkconfig.h" +#include "driver/i2c.h" +#include "driver/i2s_std.h" +#include "esp_codec_dev.h" + +#define BSP_I2C_SCL (GPIO_NUM_18) +#define BSP_I2C_SDA (GPIO_NUM_8) + +#define BSP_I2S_SCLK (GPIO_NUM_17) +#define BSP_I2S_MCLK (GPIO_NUM_2) +#define BSP_I2S_LCLK (GPIO_NUM_47) +#define BSP_I2S_DOUT (GPIO_NUM_15) // To Codec ES8311 +#define BSP_I2S_DSIN (GPIO_NUM_16) // From ADC ES7210 +#define BSP_POWER_AMP_IO (GPIO_NUM_46) +#define BSP_MUTE_STATUS (GPIO_NUM_1) + +#define BSP_I2C_NUM CONFIG_BSP_I2C_NUM + +esp_err_t bsp_i2c_init(void); +esp_err_t bsp_audio_init(const i2s_std_config_t *i2s_config); +esp_codec_dev_handle_t bsp_audio_codec_speaker_init(void); + + +#endif diff --git a/examples/boot_greeting/main/bsp/esp-bsp.h b/examples/boot_greeting/main/bsp/esp-bsp.h new file mode 100644 index 0000000..eeef765 --- /dev/null +++ b/examples/boot_greeting/main/bsp/esp-bsp.h @@ -0,0 +1,2 @@ +#pragma once +#include "esp-box.h" diff --git a/examples/boot_greeting/main/idf_component.yml b/examples/boot_greeting/main/idf_component.yml new file mode 100644 index 0000000..efe3033 --- /dev/null +++ b/examples/boot_greeting/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + espressif/esp_codec_dev: "~1.0.0" + dius/picotts: + version: "~1.0.0" + override_path: "../../../" diff --git a/examples/boot_greeting/partitions.csv b/examples/boot_greeting/partitions.csv new file mode 100644 index 0000000..ad14ffb --- /dev/null +++ b/examples/boot_greeting/partitions.csv @@ -0,0 +1,7 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, , 0x6000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 2500K, +picotts_ta, 0x40, 0x0, , 640K, +picotts_sg, 0x40, 0x1, , 820K, diff --git a/examples/boot_greeting/sdkconfig.defaults b/examples/boot_greeting/sdkconfig.defaults new file mode 100644 index 0000000..c19f977 --- /dev/null +++ b/examples/boot_greeting/sdkconfig.defaults @@ -0,0 +1,22 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.3.0 Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 +CONFIG_ESPTOOLPY_FLASHMODE_QIO=y +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_80M=y +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=n +CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y +CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744 +CONFIG_LWIP_TCP_WND_DEFAULT=5744 +CONFIG_CODEC_ES7243_SUPPORT=n +CONFIG_CODEC_ES7243E_SUPPORT=n +CONFIG_CODEC_ES8156_SUPPORT=n +CONFIG_CODEC_ES8374_SUPPORT=n +CONFIG_CODEC_ES8388_SUPPORT=n +CONFIG_CODEC_TAS5805M_SUPPORT=n diff --git a/idf_component.yml b/idf_component.yml new file mode 100644 index 0000000..3510e55 --- /dev/null +++ b/idf_component.yml @@ -0,0 +1,6 @@ +version: "1.0.0" +description: "PicoTTS Text-to-Speech engine" +license: "Apache-2.0" +maintainers: + - J Mattsson +url: "https://github.com/DiUS/esp-picotts" diff --git a/include/picotts.h b/include/picotts.h new file mode 100644 index 0000000..8185063 --- /dev/null +++ b/include/picotts.h @@ -0,0 +1,54 @@ +#include +#include + +#define PICOTTS_SAMPLE_FREQ_HZ 16000 +#define PICOTTS_SAMPLE_BITS 16 + +typedef void (*picotts_output_fn)(int16_t *samples, unsigned count); + +/** + * Initialises the PicoTTS engine and prepares to receive TTS requests. + * A new task is launched, which is used to run the TTS engine. + * @param prio The priority of the TTS task. + * @param output_cb Callback function which gets invoked directly from the + * TTS task with a buffer of samples generated. + * @param core The core number to bind the TTS task to, or -1 for no fixed + * core affinity. + * @returns True on success, false on failure. + */ +bool picotts_init(unsigned prio, picotts_output_fn output_cb, int core); + +/** + * Adds text to be synthesised. The TTS engine will wait until it sees + * an appropriate stop (e.g. sentence stop, \0) before commencing the + * speech generation. + * + * A queue is used to transfer the text to the TTS engine. The queue + * size may be configured via Kconfig. Adding more text while the queue + * is full will cause this function to block. + * + * @param txt The pointer to the text to be spoken, in UTF8 format. The + * text is copied, so the pointer may be invalidated immediately upon + * return from this call. + * @param len The number of bytes available in @c text. + */ +void picotts_add(const char *txt, unsigned len); + +/** + * Stops the TTS engine task and frees the used memory resources. + * Call @c picotts_init() again to reinitialise, if needed. + */ +void picotts_shutdown(); + + +typedef void (*picotts_error_notify_fn)(void); + +/** + * Sets a callback function to be invoked if picotts encounters and error + * and aborts. + * @param cb The callback handler. Invoked from the TTS task prior to said + * task exiting. To resume TTS operation the callback should schedule a + * reinitialisation of PicoTTS, i.e @c picotts_shutdown() followed by + * @c picotts_init(). Pass NULL to unregister a set callback function. + */ +void picotts_set_error_notify(picotts_error_notify_fn cb); diff --git a/pico/lang/de-DE_gl0_sg.bin b/pico/lang/de-DE_gl0_sg.bin new file mode 100755 index 0000000..1655704 Binary files /dev/null and b/pico/lang/de-DE_gl0_sg.bin differ diff --git a/pico/lang/de-DE_ta.bin b/pico/lang/de-DE_ta.bin new file mode 100755 index 0000000..3cb978a Binary files /dev/null and b/pico/lang/de-DE_ta.bin differ diff --git a/pico/lang/en-GB_kh0_sg.bin b/pico/lang/en-GB_kh0_sg.bin new file mode 100755 index 0000000..57c544a Binary files /dev/null and b/pico/lang/en-GB_kh0_sg.bin differ diff --git a/pico/lang/en-GB_ta.bin b/pico/lang/en-GB_ta.bin new file mode 100755 index 0000000..5050583 Binary files /dev/null and b/pico/lang/en-GB_ta.bin differ diff --git a/pico/lang/en-US_lh0_sg.bin b/pico/lang/en-US_lh0_sg.bin new file mode 100755 index 0000000..b2dfc39 Binary files /dev/null and b/pico/lang/en-US_lh0_sg.bin differ diff --git a/pico/lang/en-US_ta.bin b/pico/lang/en-US_ta.bin new file mode 100755 index 0000000..943f57e Binary files /dev/null and b/pico/lang/en-US_ta.bin differ diff --git a/pico/lang/es-ES_ta.bin b/pico/lang/es-ES_ta.bin new file mode 100755 index 0000000..3442eed Binary files /dev/null and b/pico/lang/es-ES_ta.bin differ diff --git a/pico/lang/es-ES_zl0_sg.bin b/pico/lang/es-ES_zl0_sg.bin new file mode 100755 index 0000000..c70257c Binary files /dev/null and b/pico/lang/es-ES_zl0_sg.bin differ diff --git a/pico/lang/fr-FR_nk0_sg.bin b/pico/lang/fr-FR_nk0_sg.bin new file mode 100755 index 0000000..9a11e2b Binary files /dev/null and b/pico/lang/fr-FR_nk0_sg.bin differ diff --git a/pico/lang/fr-FR_ta.bin b/pico/lang/fr-FR_ta.bin new file mode 100755 index 0000000..6d4d72e Binary files /dev/null and b/pico/lang/fr-FR_ta.bin differ diff --git a/pico/lang/it-IT_cm0_sg.bin b/pico/lang/it-IT_cm0_sg.bin new file mode 100755 index 0000000..62d236b Binary files /dev/null and b/pico/lang/it-IT_cm0_sg.bin differ diff --git a/pico/lang/it-IT_ta.bin b/pico/lang/it-IT_ta.bin new file mode 100755 index 0000000..80baa46 Binary files /dev/null and b/pico/lang/it-IT_ta.bin differ diff --git a/pico/lib/NOTICE b/pico/lib/NOTICE new file mode 100644 index 0000000..125613b --- /dev/null +++ b/pico/lib/NOTICE @@ -0,0 +1,190 @@ + + Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/pico/lib/picoacph.c b/pico/lib/picoacph.c new file mode 100644 index 0000000..5725076 --- /dev/null +++ b/pico/lib/picoacph.c @@ -0,0 +1,1435 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picoacph.c + * + * accentuation and phrasing + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include "picoos.h" +#include "picodbg.h" +#include "picobase.h" +#include "picodata.h" +#include "picoacph.h" +#include "picokdt.h" +#include "picoklex.h" +#include "picoktab.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +/* PU acphStep states */ +#define SA_STEPSTATE_COLLECT 0 +#define SA_STEPSTATE_PROCESS_PHR 12 +#define SA_STEPSTATE_PROCESS_ACC 13 +#define SA_STEPSTATE_FEED 2 + + +/* boundary strength state */ +#define SA_BOUNDSTRENGTH_SSEP 0 /* sentence separator */ +#define SA_BOUNDSTRENGTH_PPHR 1 /* primary phrase separator */ + + +/* subobject : AccPhrUnit + * shortcut : acph + * context size : one phrase, max. 30 non-PUNC items, for non-processed items + * one item if internal input empty + */ + +/** + * @addtogroup picoacph + * + * Pico Accentuation and Phrasing \n + * + internal buffers: + + - headx : array for extended item heads of fixed size (head plus + index for content, plus two fields for boundary strength/type) + - cbuf : buffer for item contents (referenced by index in + headx). + + 0. bottom up filling of items in headx and cbuf + + 1. phrasing (right-to-left): + + e.g. from WP WP WP WP WP PUNC WP WP PUNC WP WP WP PUNC FLUSH \n + e.g. to BSBEG WP WP WP BPHR3 WP WP BPHR1 WP WP BSEND BSBEG WP WP WP BSEND BTERM \n + |1 |2 |3 |4 \n + + 2-level bound state: The internal buffer contains one primary phrase (sometimes forced, if buffer + allmost full), with the trailing PUNCT item included (last item).\n + If the trailing PUNC is a a primary phrase separator, the + item is not output, but instead, the bound state is set to PPHR, so that the correct BOUND can + be output at the start of the next primary phrase.\n + Otherwise, + the item is converted to the corresponding BOUND and output. the bound state is set to SSEP, + so that a BOUND of type SBEG is output at the start of the next primary phrase. + + trailing PUNC item bound states \n + SSEP PPHR \n + PUNC(SENTEND, X) B(B,X)>SSEP B(P1,X)>SSEP (X = T | Q | E) \n + PUNC(FLUSH, T) B(B,T)>SSEP* B(P1,T)>SSEP \n + PUNC(PHRASEEND, P) B(B,P)>PPHR B(P1,P)>PPHR \n + PUNC(PHRASEEND, FORC) B(B,P)>PPHR B(P1,P)>PPHR \n + + If more than one sentence separators follow each other (e.g. SEND-FLUSH, SEND-SEND) then + all but the first will be treated as an (empty) phrase containing just this item. + If this (single) item is a flush, creation of SBEG is suppressed. + + + - dtphr phrasing tree ("subphrasing") + determines + - BOUND_PHR2 + - BOUND_PHR3 + - boundary strenghts are determined for every word (except the + first one) from right-to-left. The boundary types mark the phrase + type of the phrase following the boundary. + - number of items actually changed (new BOUND items added): because + of fixed size without content, two fields are contained in headx + to indicate if a BOUND needs to be added to the LEFT of the item. + -> headx further extended with boundary strength and type info to + indicate that to the left of the headx ele a BOUND needs to be + inserted when outputting. + + 2. accentuation: + - number of items unchanged, content unchanged, only head info changes + -> changed in place in headx +*/ + + +typedef struct { + picodata_itemhead_t head; + picoos_uint16 cind; + picoos_uint8 boundstrength; /* bstrength to the left, 0 if not set */ + picoos_uint8 boundtype; /* btype for following phrase, 0 if not set */ +} picoacph_headx_t; + + +typedef struct acph_subobj { + picoos_uint8 procState; /* for next processing step decision */ + picoos_uint8 boundStrengthState; /* boundary strength state */ + + picoos_uint8 inspaceok; /* flag: headx/cbuf has space for an item */ + picoos_uint8 needsmoreitems; /* flag: need more items */ + + picoos_uint8 tmpbuf[PICODATA_MAX_ITEMSIZE]; /* tmp. location for an item */ + + picoacph_headx_t headx[PICOACPH_MAXNR_HEADX]; + picoos_uint16 headxBottom; /* bottom */ + picoos_uint16 headxLen; /* length, 0 if empty */ + + picoos_uint8 cbuf[PICOACPH_MAXSIZE_CBUF]; + picoos_uint16 cbufBufSize; /* actually allocated size */ + picoos_uint16 cbufLen; /* length, 0 if empty */ + + /* tab knowledge base */ + picoktab_Phones tabphones; + + /* dtphr knowledge base */ + picokdt_DtPHR dtphr; + + /* dtacc knowledge base */ + picokdt_DtACC dtacc; +} acph_subobj_t; + + +static pico_status_t acphInitialize(register picodata_ProcessingUnit this, picoos_int32 resetMode) { + acph_subobj_t * acph; + picoos_uint16 i; + + PICODBG_DEBUG(("calling")); + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(this->common->em, + PICO_ERR_NULLPTR_ACCESS, NULL, NULL); + } + acph = (acph_subobj_t *) this->subObj; + acph->procState = SA_STEPSTATE_COLLECT; + acph->boundStrengthState = SA_BOUNDSTRENGTH_SSEP; + + acph->inspaceok = TRUE; + acph->needsmoreitems = TRUE; + + acph->headxBottom = 0; + acph->headxLen = 0; + acph->cbufBufSize = PICOACPH_MAXSIZE_CBUF; + acph->cbufLen = 0; + + /* init headx, cbuf */ + for (i = 0; i < PICOACPH_MAXNR_HEADX; i++){ + acph->headx[i].head.type = 0; + acph->headx[i].head.info1 = 0; + acph->headx[i].head.info2 = 0; + acph->headx[i].head.len = 0; + acph->headx[i].cind = 0; + acph->headx[i].boundstrength = 0; + acph->headx[i].boundtype = 0; + } + for (i = 0; i < PICOACPH_MAXSIZE_CBUF; i++) { + acph->cbuf[i] = 0; + } + + if (resetMode == PICO_RESET_SOFT) { + /*following initializations needed only at startup or after a full reset*/ + return PICO_OK; + } + + /* kb tabphones */ + acph->tabphones = + picoktab_getPhones(this->voice->kbArray[PICOKNOW_KBID_TAB_PHONES]); + if (acph->tabphones == NULL) { + return picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + PICODBG_DEBUG(("got tabphones")); + +#ifdef PICO_DEBUG_1 + { + picoos_uint16 itmp; + for (itmp = 0; itmp < 256; itmp++) { + if (picoktab_hasVowelProp(acph->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones hasVowel: %d", itmp)); + } + if (picoktab_hasDiphthProp(acph->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones hasDiphth: %d", itmp)); + } + if (picoktab_hasGlottProp(acph->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones hasGlott: %d", itmp)); + } + if (picoktab_hasNonsyllvowelProp(acph->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones hasNonsyllvowel: %d", itmp)); + } + if (picoktab_hasSyllconsProp(acph->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones hasSyllcons: %d", itmp)); + } + + if (picoktab_isPrimstress(acph->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones isPrimstress: %d", itmp)); + } + if (picoktab_isSecstress(acph->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones isSecstress: %d", itmp)); + } + if (picoktab_isSyllbound(acph->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones isSyllbound: %d", itmp)); + } + if (picoktab_isPause(acph->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones isPause: %d", itmp)); + } + } + + PICODBG_DEBUG(("tabphones primstressID: %d", + picoktab_getPrimstressID(acph->tabphones))); + PICODBG_DEBUG(("tabphones secstressID: %d", + picoktab_getSecstressID(acph->tabphones))); + PICODBG_DEBUG(("tabphones syllboundID: %d", + picoktab_getSyllboundID(acph->tabphones))); + PICODBG_DEBUG(("tabphones pauseID: %d", + picoktab_getPauseID(acph->tabphones))); + } +#endif + + + /* kb dtphr */ + acph->dtphr = picokdt_getDtPHR(this->voice->kbArray[PICOKNOW_KBID_DT_PHR]); + if (acph->dtphr == NULL) { + return picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + PICODBG_DEBUG(("got dtphr")); + + /* kb dtacc */ + acph->dtacc = picokdt_getDtACC(this->voice->kbArray[PICOKNOW_KBID_DT_ACC]); + if (acph->dtacc == NULL) { + return picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + PICODBG_DEBUG(("got dtacc")); + + return PICO_OK; +} + +static picodata_step_result_t acphStep(register picodata_ProcessingUnit this, + picoos_int16 mode, + picoos_uint16 *numBytesOutput); + +static pico_status_t acphTerminate(register picodata_ProcessingUnit this) +{ + return PICO_OK; +} + +static pico_status_t acphSubObjDeallocate(register picodata_ProcessingUnit this, + picoos_MemoryManager mm) { + mm = mm; /* avoid warning "var not used in this function"*/ + if (NULL != this) { + picoos_deallocate(this->common->mm, (void *) &this->subObj); + } + return PICO_OK; +} + + +picodata_ProcessingUnit picoacph_newAccPhrUnit(picoos_MemoryManager mm, + picoos_Common common, + picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, + picorsrc_Voice voice) { + picodata_ProcessingUnit this; + + this = picodata_newProcessingUnit(mm, common, cbIn, cbOut, voice); + if (this == NULL) { + return NULL; + } + + this->initialize = acphInitialize; + PICODBG_DEBUG(("set this->step to acphStep")); + this->step = acphStep; + this->terminate = acphTerminate; + this->subDeallocate = acphSubObjDeallocate; + this->subObj = picoos_allocate(mm, sizeof(acph_subobj_t)); + if (this->subObj == NULL) { + picoos_deallocate(mm, (void *)&this); + picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, NULL, NULL); + return NULL; + } + + acphInitialize(this, PICO_RESET_FULL); + return this; +} + + +/* ***********************************************************************/ +/* PROCESS_PHR/ACC support functions */ +/* ***********************************************************************/ + + +static picoos_uint8 acphGetNrSylls(register picodata_ProcessingUnit this, + register acph_subobj_t *acph, + const picoos_uint16 ind) { + picoos_uint8 i; + picoos_uint8 ch; + picoos_uint8 count; + + count = 1; + for (i = 0; i < acph->headx[ind].head.len; i++) { + ch = acph->cbuf[acph->headx[ind].cind + i]; + if (picoktab_isSyllbound(acph->tabphones, ch)) { + count++; + } + } + return count; +} + + +/* ***********************************************************************/ +/* PROCESS_PHR functions */ +/* ***********************************************************************/ + + +/* find next POS to the left of 'ind' and return its POS and index */ +static picoos_uint8 acphPhrItemSeqGetPosLeft(register picodata_ProcessingUnit this, + register acph_subobj_t *acph, + const picoos_uint16 ind, + picoos_uint16 *leftind) { + picoos_uint8 val; + picoos_int32 i; + + val = PICOKDT_EPSILON; + for (i = ind - 1; ((val == PICOKDT_EPSILON) && (i >= 0)); i--) { + if (acph->headx[i].head.type == PICODATA_ITEM_WORDPHON) { + val = acph->headx[i].head.info1; + } + } + *leftind = i + 1; + return val; +} + + +/* right-to-left, for each WORDPHON do phr */ +static pico_status_t acphSubPhrasing(register picodata_ProcessingUnit this, + register acph_subobj_t *acph) { + picokdt_classify_result_t dtres; + picoos_uint8 valbuf[5]; + picoos_uint16 nrwordspre; + picoos_uint16 nrwordsfol; + picoos_uint16 nrsyllsfol; + picoos_uint16 lastprev2; /* last index of POS(es) found to the left */ + picoos_uint8 curpos; /* POS(es) of current word */ + picoos_uint16 upbound; /* index of last WORDPHON item (with POS) */ + picoos_uint8 okay; + picoos_uint8 nosubphrases; + picoos_int32 i; + + /* set initial values */ + okay = TRUE; + nosubphrases = TRUE; + curpos = PICOKDT_EPSILON; /* needs to be in 2^8 */ + + /* set upbound to last WORDPHON, don't worry about first one */ + upbound = acph->headxLen - 1; + while ((upbound > 0) && + (acph->headx[upbound].head.type != PICODATA_ITEM_WORDPHON)) { + upbound--; + } + + /* zero or one WORDPHON, no subphrasing needed, but handling of + BOUND strength state is needed */ + if (upbound <= 0) { + /* phrase not containing more than one WORDPHON */ + PICODBG_DEBUG(("less than two WORDPHON in phrase -> no subphrasing")); + } + + lastprev2 = upbound; + + /* set initial nr pre/fol words/sylls, upbound is ind of last WORDPHON */ + nrwordsfol = 0; + nrsyllsfol = 0; + nrwordspre = 0; + for (i = 0; i < upbound; i++) { + if (acph->headx[i].head.type == PICODATA_ITEM_WORDPHON) { + nrwordspre++; + } + } + + nrwordspre++; /* because we later have a decrement before being used */ + + + /* set POS of current word in valbuf[1], will be shifted right afterwards */ + valbuf[1] = acph->headx[upbound].head.info1; + /* find first POS to the left and set valbuf[0] */ + valbuf[0] = acphPhrItemSeqGetPosLeft(this, acph, lastprev2, &lastprev2); + for (i = 2; i < 5; i++) { + valbuf[i] = PICOKDT_EPSILON; + } + + PICODBG_TRACE(("headxLen: %d", acph->headxLen)); + + /* at least two WORDPHON items */ + /* process from right-to-left all items in headx, except for 1st WORDPHON */ + for (i = upbound; (i > 0) && (nrwordspre > 1); i--) { + okay = TRUE; + + PICODBG_TRACE(("iter: %d, type: %c", i, acph->headx[i].head.type)); + + /* if not (WORDPHON) */ + if ((acph->headx[i].head.type != PICODATA_ITEM_WORDPHON)) { + continue; + } + + PICODBG_TRACE(("iter: %d, curpos: %d", i, acph->headx[i].head.info1)); + + /* get and set POS of current item, must be WORDPHON */ + curpos = acph->headx[i].head.info1; + + /* no continue so far => at [i] we have a WORDPHON item */ + /* shift all POS elements one position to the right */ + valbuf[4] = valbuf[3]; + valbuf[3] = valbuf[2]; + valbuf[2] = valbuf[1]; + valbuf[1] = valbuf[0]; + /* find next POS to the left and set valbuf[0] */ + valbuf[0] = acphPhrItemSeqGetPosLeft(this, acph, lastprev2, &lastprev2); + + /* better check double than never */ + if (curpos != valbuf[2]) { + PICODBG_WARN(("syncing POS")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_INVECTOR, + NULL, NULL); + valbuf[2] = curpos; + } + + nrwordsfol++; + nrsyllsfol += acphGetNrSylls(this, acph, i); + nrwordspre--; + + PICODBG_TRACE(("%d: [%d,%d|%d|%d,%d|%d,%d,%d]", + i, valbuf[0], valbuf[1], valbuf[2], valbuf[3], + valbuf[4], nrwordspre, nrwordsfol, nrsyllsfol)); + + /* no continue so far => subphrasing needed */ + /* construct input vector, which is set in dtphr */ + if (!picokdt_dtPHRconstructInVec(acph->dtphr, valbuf[0], valbuf[1], + valbuf[2], valbuf[3], valbuf[4], + nrwordspre, nrwordsfol, nrsyllsfol)) { + /* error constructing invec */ + PICODBG_WARN(("problem with invec")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_INVECTOR, + NULL, NULL); + okay = FALSE; + } + /* classify */ + if (okay && (!picokdt_dtPHRclassify(acph->dtphr))) { + /* error doing classification */ + PICODBG_WARN(("problem classifying")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_CLASSIFICATION, + NULL, NULL); + okay = FALSE; + } + /* decompose */ + if (okay && (!picokdt_dtPHRdecomposeOutClass(acph->dtphr, &dtres))) { + /* error decomposing */ + PICODBG_WARN(("problem decomposing")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_OUTVECTOR, + NULL, NULL); + okay = FALSE; + } + + if (okay && dtres.set) { + PICODBG_DEBUG(("%d - inpos: %d, out: %d", i,valbuf[2],dtres.class)); + } else { + PICODBG_WARN(("problem determining subphrase boundary strength")); + dtres.class = PICODATA_ITEMINFO1_ERR; + } + + if (dtres.class > 255) { + PICODBG_WARN(("dt class outside valid range, setting to PHR0")); + dtres.class = PICODATA_ITEMINFO1_BOUND_PHR0; + } + acph->headx[i].boundstrength = (picoos_uint8)dtres.class; + if ((dtres.class == PICODATA_ITEMINFO1_BOUND_PHR2) || + (dtres.class == PICODATA_ITEMINFO1_BOUND_PHR3)) { + if (nosubphrases) { + /* it's the last secondary phrase in the primary phrase */ + /* add type info */ + switch (acph->headx[acph->headxLen - 1].head.info2) { + case PICODATA_ITEMINFO2_PUNC_SENT_T: + acph->headx[i].boundtype = + PICODATA_ITEMINFO2_BOUNDTYPE_T; + break; + case PICODATA_ITEMINFO2_PUNC_SENT_Q: + acph->headx[i].boundtype = + PICODATA_ITEMINFO2_BOUNDTYPE_Q; + break; + case PICODATA_ITEMINFO2_PUNC_SENT_E: + acph->headx[i].boundtype = + PICODATA_ITEMINFO2_BOUNDTYPE_E; + break; + case PICODATA_ITEMINFO2_PUNC_PHRASE: + case PICODATA_ITEMINFO2_PUNC_PHRASE_FORCED: + acph->headx[i].boundtype = + PICODATA_ITEMINFO2_BOUNDTYPE_P; + break; + default: + PICODBG_WARN(("invalid boundary type, not set")); + break; + } + nosubphrases = FALSE; + + } else { + acph->headx[i].boundtype = + PICODATA_ITEMINFO2_BOUNDTYPE_P; + } + /* reset nr following words and sylls counters */ + nrwordsfol = 0; + nrsyllsfol = 0; + } + } + + /* process first item, add bound-info */ + switch (acph->boundStrengthState) { + case SA_BOUNDSTRENGTH_SSEP: + acph->headx[0].boundstrength = + PICODATA_ITEMINFO1_BOUND_SBEG; + break; + case SA_BOUNDSTRENGTH_PPHR: + acph->headx[0].boundstrength = + PICODATA_ITEMINFO1_BOUND_PHR1; + break; + default: + PICODBG_WARN(("invalid boundary strength, not set")); + break; + } + + /* set boundary strength state */ + switch (acph->headx[acph->headxLen - 1].head.info1) { + case PICODATA_ITEMINFO1_PUNC_SENTEND: + case PICODATA_ITEMINFO1_PUNC_FLUSH: + acph->boundStrengthState = SA_BOUNDSTRENGTH_SSEP; + break; + case PICODATA_ITEMINFO1_PUNC_PHRASEEND: + acph->boundStrengthState = SA_BOUNDSTRENGTH_PPHR; + break; + default: + PICODBG_WARN(("invalid boundary strength state, not changed")); + break; + } + + if (nosubphrases) { + /* process first item, add type info */ + switch (acph->headx[acph->headxLen - 1].head.info2) { + case PICODATA_ITEMINFO2_PUNC_SENT_T: + acph->headx[0].boundtype = + PICODATA_ITEMINFO2_BOUNDTYPE_T; + break; + case PICODATA_ITEMINFO2_PUNC_SENT_Q: + acph->headx[0].boundtype = + PICODATA_ITEMINFO2_BOUNDTYPE_Q; + break; + case PICODATA_ITEMINFO2_PUNC_SENT_E: + acph->headx[0].boundtype = + PICODATA_ITEMINFO2_BOUNDTYPE_E; + break; + case PICODATA_ITEMINFO2_PUNC_PHRASE: + case PICODATA_ITEMINFO2_PUNC_PHRASE_FORCED: + acph->headx[0].boundtype = + PICODATA_ITEMINFO2_BOUNDTYPE_P; + break; + default: + PICODBG_WARN(("invalid boundary type, not set")); + break; + } + } else { + acph->headx[0].boundtype = + PICODATA_ITEMINFO2_BOUNDTYPE_P; + } + + return PICO_OK; +} + + +/* ***********************************************************************/ +/* PROCESS_ACC functions */ +/* ***********************************************************************/ + +/* find next POS to the left of 'ind' and return its POS and index */ +static picoos_uint8 acphAccItemSeqGetPosLeft(register picodata_ProcessingUnit this, + register acph_subobj_t *acph, + const picoos_uint16 ind, + picoos_uint16 *leftind) { + picoos_uint8 val; + picoos_int32 i; + + val = PICOKDT_EPSILON; + for (i = ind - 1; ((val == PICOKDT_EPSILON) && (i >= 0)); i--) { + if (acph->headx[i].head.type == PICODATA_ITEM_WORDPHON) { + val = acph->headx[i].head.info1; + } + } + *leftind = i + 1; + return val; +} + + +/* s1: nr sylls in word before the first primary stressed syll, + s2: nr sylls in word after (but excluding) the first primary stressed syll */ +static picoos_uint8 acphAccNrSyllParts(register picodata_ProcessingUnit this, + register acph_subobj_t *acph, + const picoos_uint16 ind, + picoos_uint8 *s1, + picoos_uint8 *s2) { + picoos_uint16 pind; + picoos_uint16 pend; /* phone string start+len */ + picoos_uint8 afterprim; + + /* check ind is in valid range */ + if (ind >= acph->headxLen) { + return FALSE; + } + + *s1 = 0; + *s2 = 0; + afterprim = FALSE; + pend = acph->headx[ind].cind + acph->headx[ind].head.len; + for (pind = acph->headx[ind].cind; pind < pend; pind++) { + if (picoktab_isPrimstress(acph->tabphones, acph->cbuf[pind])) { + afterprim = TRUE; + } else if (picoktab_isSyllbound(acph->tabphones, acph->cbuf[pind])) { + if (afterprim) { + (*s2)++; + } else { + (*s1)++; + } + } + } + if (afterprim) { + (*s2)++; + } else { + (*s1)++; + } + + /* exclude the stressed syllable */ + if ((*s2) > 0) { + (*s2)--; + } + /* handle the case when there is no primstress */ + if (!afterprim) { + (*s2) = (*s1); + } + return TRUE; +} + + +static picoos_uint8 acphAccGetNrsRight(register picodata_ProcessingUnit this, + register acph_subobj_t *acph, + const picoos_uint16 ind, + picoos_uint16 *nrwordsfol, + picoos_uint16 *nrsyllsfol, + picoos_uint16 *footwordsfol, + picoos_uint16 *footsyllsfol) { + picoos_uint16 i; + picoos_uint8 s1; + picoos_uint8 s2; + + if (!acphAccNrSyllParts(this, acph, ind, &s1, &s2)) { + return FALSE; + } + + *nrwordsfol = 0; + *nrsyllsfol = s2; + i = ind + 1; + while ((i < acph->headxLen) && + (acph->headx[i].boundstrength == PICODATA_ITEMINFO1_BOUND_PHR0)) { + if (acph->headx[i].head.type == PICODATA_ITEM_WORDPHON) { + (*nrwordsfol)++; + *nrsyllsfol += acphGetNrSylls(this, acph, i); + } + i++; + } + + *footwordsfol = 0; + *footsyllsfol = s2; + i = ind + 1; + while ((i < acph->headxLen) && + (acph->headx[i].head.info2 != PICODATA_ACC1)) { + if (acph->headx[i].head.type == PICODATA_ITEM_WORDPHON) { + (*footwordsfol)++; + *footsyllsfol += acphGetNrSylls(this, acph, i); + } + i++; + } + if ((i < acph->headxLen) && (acph->headx[i].head.info2 == PICODATA_ACC1)) { + if (!acphAccNrSyllParts(this, acph, i, &s1, &s2)) { + return FALSE; + } + *footsyllsfol += s1; + } + return TRUE; +} + + +static picoos_uint8 acphAccGetNrsLeft(register picodata_ProcessingUnit this, + register acph_subobj_t *acph, + const picoos_uint16 ind, + picoos_uint16 *nrwordspre, + picoos_uint16 *nrsyllspre) { + picoos_int32 i; + picoos_uint8 s1; + picoos_uint8 s2; + + if (!acphAccNrSyllParts(this, acph, ind, &s1, &s2)) { + return FALSE; + } + + *nrwordspre = 0; + *nrsyllspre = s1; + i = ind - 1; + while ((i >= 0) && + (acph->headx[i].boundstrength == PICODATA_ITEMINFO1_BOUND_PHR0)) { + if (acph->headx[i].head.type == PICODATA_ITEM_WORDPHON) { + (*nrwordspre)++; + *nrsyllspre += acphGetNrSylls(this, acph, i); + } + i--; + } + + if (i > 0 && (acph->headx[i].boundstrength != PICODATA_ITEMINFO1_BOUND_PHR0) && + (acph->headx[i].head.type == PICODATA_ITEM_WORDPHON)) { + (*nrwordspre)++; + *nrsyllspre += acphGetNrSylls(this, acph, i); + } + return TRUE; +} + + +/* return TRUE if wordphon contains no stress, FALSE otherwise */ +static picoos_uint8 acphIsWordWithoutStress(register picodata_ProcessingUnit this, + register acph_subobj_t *acph, + const picoos_uint16 ind) { + picoos_uint8 i; + picoos_uint16 pos; + + pos = acph->headx[ind].cind; + for (i = 0; i < acph->headx[ind].head.len; i++) { + if (picoktab_isPrimstress(acph->tabphones, acph->cbuf[pos + i]) || + picoktab_isSecstress(acph->tabphones, acph->cbuf[pos + i])) { + return FALSE; + } + } + return TRUE; +} + + +/* right-to-left, for each WORDPHON do acc */ +static pico_status_t acphAccentuation(register picodata_ProcessingUnit this, + register acph_subobj_t *acph) { + picokdt_classify_result_t dtres; + picoos_uint8 valbuf[5]; + picoos_uint16 hist1; + picoos_uint16 hist2; + picoos_uint16 nrwordspre; + picoos_uint16 nrsyllspre; + picoos_uint16 nrwordsfol; + picoos_uint16 nrsyllsfol; + picoos_uint16 footwordsfol; + picoos_uint16 footsyllsfol; + picoos_uint16 lastprev2; /* last index of POS(es) found to the left */ + picoos_uint8 curpos; /* POS(es) of current word */ + picoos_uint16 prevout; + picoos_uint8 okay; + picoos_int32 upbound; /* index of last WORDPHON item (with POS) */ + picoos_uint16 i; + + /* set initial values */ + okay = TRUE; + curpos = PICOKDT_EPSILON; /* needs to be < 2^8 */ + + /* set upbound to last WORDPHON */ + upbound = acph->headxLen - 1; + while ((upbound >= 0) && + (acph->headx[upbound].head.type != PICODATA_ITEM_WORDPHON)) { + upbound--; + } + + if (upbound < 0) { + /* phrase containing zero WORDPHON */ + PICODBG_DEBUG(("no WORDPHON in phrase -> no accentuation")); + return PICO_OK; + } + + lastprev2 = upbound; + + /* set initial history values */ + prevout = PICOKDT_HISTORY_ZERO; + hist1 = PICOKDT_HISTORY_ZERO; + hist2 = PICOKDT_HISTORY_ZERO; + + /* set initial nr pre/fol words/sylls, upbound is ind of last WORDPHON */ + nrwordsfol = 0; + nrsyllsfol = 0; + footwordsfol = 0; + footsyllsfol = 0; + nrwordspre = 0; + nrsyllspre = 0; + + /* set POS of current word in valbuf[1], will be shifted right afterwards */ + valbuf[1] = acph->headx[upbound].head.info1; + /* find first POS to the left and set valbuf[0] */ + valbuf[0] = acphAccItemSeqGetPosLeft(this, acph, lastprev2, &lastprev2); + for (i = 2; i < 5; i++) { + valbuf[i] = PICOKDT_EPSILON; + } + + PICODBG_TRACE(("headxLen: %d", acph->headxLen)); + + /* process from right-to-left all items in headx */ + for (i = upbound+1; i > 0; ) { + i--; + + okay = TRUE; + + PICODBG_TRACE(("iter: %d, type: %c", i, acph->headx[i].head.type)); + + /* if not (WORDPHON) */ + if ((acph->headx[i].head.type != PICODATA_ITEM_WORDPHON)) { + continue; + } + + PICODBG_TRACE(("iter: %d, curpos: %d", i, acph->headx[i].head.info1)); + + /* get and set POS of current item, must be WORDPHON */ + curpos = acph->headx[i].head.info1; + + /* no continue so far => at [i] we have a WORDPHON item */ + /* shift all POS elements one position to the right */ + valbuf[4] = valbuf[3]; + valbuf[3] = valbuf[2]; + valbuf[2] = valbuf[1]; + valbuf[1] = valbuf[0]; + /* find next POS to the left and set valbuf[0] */ + valbuf[0] = acphAccItemSeqGetPosLeft(this, acph, lastprev2, &lastprev2); + + /* better check double than never */ + if (curpos != valbuf[2]) { + PICODBG_WARN(("syncing POS")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_INVECTOR, + NULL, NULL); + valbuf[2] = curpos; + } + + /* set history values */ + hist2 = hist1; + hist1 = prevout; + + /* ************************************************************ */ + /* many speedups possible by avoiding double calc of attribtues */ + /* ************************************************************ */ + + /* get distances */ + if ((!acphAccGetNrsRight(this, acph, i, &nrwordsfol, &nrsyllsfol, + &footwordsfol, &footsyllsfol)) || + (!acphAccGetNrsLeft(this, acph, i, &nrwordspre, &nrsyllspre))) { + PICODBG_WARN(("problem setting distances in invec")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_INVECTOR, + NULL, NULL); + okay = FALSE; + } + + PICODBG_TRACE(("%d: [%d,%d,%d,%d,%d|%d,%d|%d,%d,%d,%d|%d,%d]", i, + valbuf[0], valbuf[1], valbuf[2], valbuf[3], valbuf[4], + hist1, hist2, nrwordspre, nrsyllspre, + nrwordsfol, nrsyllsfol, footwordsfol, footsyllsfol)); + + /* no continue so far => accentuation needed */ + /* construct input vector, which is set in dtacc */ + if (!picokdt_dtACCconstructInVec(acph->dtacc, valbuf[0], valbuf[1], + valbuf[2], valbuf[3], valbuf[4], + hist1, hist2, nrwordspre, nrsyllspre, + nrwordsfol, nrsyllsfol, footwordsfol, + footsyllsfol)) { + /* error constructing invec */ + PICODBG_WARN(("problem with invec")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_INVECTOR, + NULL, NULL); + okay = FALSE; + } + /* classify */ + if (okay && (!picokdt_dtACCclassify(acph->dtacc, &prevout))) { + /* error doing classification */ + PICODBG_WARN(("problem classifying")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_CLASSIFICATION, + NULL, NULL); + okay = FALSE; + } + /* decompose */ + if (okay && (!picokdt_dtACCdecomposeOutClass(acph->dtacc, &dtres))) { + /* error decomposing */ + PICODBG_WARN(("problem decomposing")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_OUTVECTOR, + NULL, NULL); + okay = FALSE; + } + + if (dtres.class > 255) { + PICODBG_WARN(("dt class outside valid range, setting to ACC0")); + dtres.class = PICODATA_ACC0; + } + + if (okay && dtres.set) { + PICODBG_DEBUG(("%d - inpos: %d, out: %d", i,valbuf[2],dtres.class)); + if (acphIsWordWithoutStress(this, acph, i)) { + if (dtres.class != PICODATA_ACC0) { + acph->headx[i].head.info2 = PICODATA_ACC3; + } else { + acph->headx[i].head.info2 = (picoos_uint8)dtres.class; + } + } else { + acph->headx[i].head.info2 = (picoos_uint8)dtres.class; + } + PICODBG_DEBUG(("%d - after-nostress-corr: %d", + i, acph->headx[i].head.info2)); + } else { + PICODBG_WARN(("problem determining accentuation level")); + dtres.class = PICODATA_ITEMINFO1_ERR; + } + } + return PICO_OK; +} + + + +/* ***********************************************************************/ +/* acphStep support functions */ +/* ***********************************************************************/ + +static picoos_uint8 acphPutBoundItem(register picodata_ProcessingUnit this, + register acph_subobj_t *acph, + const picoos_uint8 strength, + const picoos_uint8 type, + picoos_uint8 *dopuoutfull, + picoos_uint16 *numBytesOutput) { + pico_status_t rv = PICO_OK; + picoos_uint16 blen = 0; + picodata_itemhead_t tmphead; + + *dopuoutfull = FALSE; + + /* construct BOUND item in tmpbuf and put item */ + tmphead.type = PICODATA_ITEM_BOUND; + tmphead.info1 = strength; + tmphead.info2 = type; + tmphead.len = 0; + rv = picodata_put_itemparts(&tmphead, NULL, 0, acph->tmpbuf, + PICODATA_MAX_ITEMSIZE, &blen); + if (rv != PICO_OK) { + PICODBG_ERROR(("problem creating BOUND item")); + picoos_emRaiseException(this->common->em, rv, NULL, NULL); + return FALSE; + } + /* put constructed item to ext. charbuf */ + rv = picodata_cbPutItem(this->cbOut, acph->tmpbuf, blen, &blen); + + *numBytesOutput += blen; + if (rv == PICO_EXC_BUF_OVERFLOW) { + PICODBG_DEBUG(("overflow in cb output buffer")); + *dopuoutfull = TRUE; /* ie. do PU_OUT_FULL later */ + return FALSE; + } else if (rv != PICO_OK) { + PICODBG_ERROR(("problem putting BOUND item")); + picoos_emRaiseException(this->common->em, rv, NULL, NULL); + return FALSE; + } + + PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG], + (picoos_uint8 *)"acph: ", acph->tmpbuf, blen); + + return TRUE; +} + + + +/* ***********************************************************************/ +/* acphStep function */ +/* ***********************************************************************/ + +/* +complete phrase processed in one step, if not fast enough -> rework + +init, collect into internal buffer, process, and then feed to +output buffer + +init state: INIT ext ext +state trans: in hc1 hc2 out + +INIT | putItem = 0 0 +1 | BUSY -> COLL (put B-SBEG item, + set do-init to false) + + inspace-ok-hc1 + needs-more-items-(phrase-or-flush) +COLL1 |getItems -n +n 0 1 | ATOMIC -> PPOSD (got items, + if flush set do-init) +COLL2 |getItems -n +n 1 0 | ATOMIC -> PPOSD (got items, forced) +COLL3 |getItems -n +n 1 1 | IDLE (got items, need more) +COLL4 |getItems = = 1 1 | IDLE (got no items) + +PPOSD | posd = ~n~n | BUSY -> PWP (posd done) +PWP | lex/g2p = ~n-n 0+n | BUSY -> PPHR (lex/g2p done) +PPHR | phr = -n 0 +m=n | BUSY -> PACC (phr done, m>=n) +PACC | acc = 0 0 ~m=n | BUSY -> FEED (acc done) + + doinit-flag +FEED | putItems 0 0 0 -m-n +m 0 | BUSY -> COLL (put items) +FEED | putItems 0 0 0 -m-n +m 1 | BUSY -> INIT (put items) +FEED | putItems 0 0 0 -d-d +d | OUT_FULL (put some items) +*/ + +static picodata_step_result_t acphStep(register picodata_ProcessingUnit this, + picoos_int16 mode, + picoos_uint16 *numBytesOutput) { + register acph_subobj_t *acph; + pico_status_t rv = PICO_OK; + pico_status_t rvP = PICO_OK; + picoos_uint16 blen = 0; + picoos_uint16 clen = 0; + picoos_uint16 i; + + + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + acph = (acph_subobj_t *) this->subObj; + mode = mode; /* avoid warning "var not used in this function"*/ + *numBytesOutput = 0; + while (1) { /* exit via return */ + PICODBG_DEBUG(("doing state %i, hLen|c1Len: %d|%d", + acph->procState, acph->headxLen, acph->cbufLen)); + + switch (acph->procState) { + + /* *********************************************************/ + /* collect state: get item(s) from charBuf and store in + * internal buffers, need a complete punctuation-phrase + */ + case SA_STEPSTATE_COLLECT: + + while (acph->inspaceok && acph->needsmoreitems && (PICO_OK == + (rv = picodata_cbGetItem(this->cbIn, acph->tmpbuf, + PICODATA_MAX_ITEMSIZE, &blen)))) { + rvP = picodata_get_itemparts(acph->tmpbuf, + PICODATA_MAX_ITEMSIZE, &(acph->headx[acph->headxLen].head), + &(acph->cbuf[acph->cbufLen]), acph->cbufBufSize + - acph->cbufLen, &clen); + if (rvP != PICO_OK) { + PICODBG_ERROR(("problem getting item parts")); + picoos_emRaiseException(this->common->em, rvP, + NULL, NULL); + return PICODATA_PU_ERROR; + } + + /* if CMD(...FLUSH...) -> PUNC(...FLUSH...), + construct PUNC-FLUSH item in headx */ + if ((acph->headx[acph->headxLen].head.type + == PICODATA_ITEM_CMD) + && (acph->headx[acph->headxLen].head.info1 + == PICODATA_ITEMINFO1_CMD_FLUSH)) { + acph->headx[acph->headxLen].head.type + = PICODATA_ITEM_PUNC; + acph->headx[acph->headxLen].head.info1 + = PICODATA_ITEMINFO1_PUNC_FLUSH; + acph->headx[acph->headxLen].head.info2 + = PICODATA_ITEMINFO2_PUNC_SENT_T; + acph->headx[acph->headxLen].head.len = 0; + } + + /* check/set needsmoreitems */ + if (acph->headx[acph->headxLen].head.type + == PICODATA_ITEM_PUNC) { + acph->needsmoreitems = FALSE; + } + + /* check/set inspaceok, keep spare slot for forcing */ + if ((acph->headxLen >= (PICOACPH_MAXNR_HEADX - 2)) + || ((acph->cbufBufSize - acph->cbufLen) + < PICODATA_MAX_ITEMSIZE)) { + acph->inspaceok = FALSE; + } + + if (clen > 0) { + acph->headx[acph->headxLen].cind = acph->cbufLen; + acph->cbufLen += clen; + } else { + acph->headx[acph->headxLen].cind = 0; + } + acph->headxLen++; + } + + if (!acph->needsmoreitems) { + /* 1, phrase buffered */ + acph->procState = SA_STEPSTATE_PROCESS_PHR; + return PICODATA_PU_ATOMIC; + } else if (!acph->inspaceok) { + /* 2, forced phrase end */ + /* at least one slot is still free, use it to + force a trailing PUNC item */ + acph->headx[acph->headxLen].head.type = PICODATA_ITEM_PUNC; + acph->headx[acph->headxLen].head.info1 = + PICODATA_ITEMINFO1_PUNC_PHRASEEND; + acph->headx[acph->headxLen].head.info2 = + PICODATA_ITEMINFO2_PUNC_PHRASE_FORCED; + acph->headx[acph->headxLen].head.len = 0; + acph->needsmoreitems = FALSE; /* not really needed for now */ + acph->headxLen++; + PICODBG_WARN(("forcing phrase end, added PUNC_PHRASEEND")); + picoos_emRaiseWarning(this->common->em, + PICO_WARN_FALLBACK, NULL, + (picoos_char *)"forced phrase end"); + acph->procState = SA_STEPSTATE_PROCESS_PHR; + return PICODATA_PU_ATOMIC; + } else if (rv == PICO_EOF) { + /* 3, 4 */ + return PICODATA_PU_IDLE; + } else if ((rv == PICO_EXC_BUF_UNDERFLOW) || + (rv == PICO_EXC_BUF_OVERFLOW)) { + /* error, no valid item in cb (UNDER) */ + /* or tmpbuf not large enough, not possible (OVER) */ + /* no exception raised, left for ctrl to handle */ + PICODBG_ERROR(("buffer under/overflow, rv: %d", rv)); + return PICODATA_PU_ERROR; + } else { + /* error, only possible if cbGetItem implementation + changes without this function being adapted*/ + PICODBG_ERROR(("untreated return value, rv: %d", rv)); + return PICODATA_PU_ERROR; + } + break; + + + + + /* *********************************************************/ + /* process phr state: process items in headx and modify + * headx in place + */ + case SA_STEPSTATE_PROCESS_PHR: + /* ensure there is an item in inBuf */ + if (acph->headxLen > 0) { + /* we have a phrase in headx, cbuf1 (can be + single PUNC item), do phrasing and modify headx */ + + if (PICO_OK != acphSubPhrasing(this, acph)) { + picoos_emRaiseException(this->common->em, + PICO_ERR_OTHER, NULL, NULL); + return PICODATA_PU_ERROR; + } + acph->procState = SA_STEPSTATE_PROCESS_ACC; + } else if (acph->headxLen == 0) { /* no items in inBuf */ + PICODBG_WARN(("no items in inBuf")); + acph->procState = SA_STEPSTATE_COLLECT; + return PICODATA_PU_BUSY; + } + +#if defined (PICO_DEBUG_NOTNEEDED) + if (1) { + picoos_uint8 i, j, ittype; + for (i = 0; i < acph->headxLen; i++) { + if ((acph->headx[i].boundstrength != 0) && + (acph->headx[i].boundstrength != + PICODATA_ITEMINFO1_BOUND_PHR0)) { + PICODBG_INFO(("acph-p: boundstrength '%c', " + "boundtype '%c'", + acph->headx[i].boundstrength, + acph->headx[i].boundtype)); + } + + ittype = acph->headx[i].head.type; + PICODBG_INFO_CTX(); + PICODBG_INFO_MSG(("acph-p: (")); + PICODBG_INFO_MSG(("'%c',", ittype)); + if ((32 <= acph->headx[i].head.info1) && + (acph->headx[i].head.info1 < 127) && + (ittype != PICODATA_ITEM_WORDPHON)) { + PICODBG_INFO_MSG(("'%c',",acph->headx[i].head.info1)); + } else { + PICODBG_INFO_MSG(("%3d,", acph->headx[i].head.info1)); + } + if ((32 <= acph->headx[i].head.info2) && + (acph->headx[i].head.info2 < 127)) { + PICODBG_INFO_MSG(("'%c',",acph->headx[i].head.info2)); + } else { + PICODBG_INFO_MSG(("%3d,", acph->headx[i].head.info2)); + } + PICODBG_INFO_MSG(("%3d)", acph->headx[i].head.len)); + + for (j = 0; j < acph->headx[i].head.len; j++) { + if ((ittype == PICODATA_ITEM_CMD)) { + PICODBG_INFO_MSG(("%c", + acph->cbuf[acph->headx[i].cind+j])); + } else { + PICODBG_INFO_MSG(("%4d", + acph->cbuf[acph->headx[i].cind+j])); + } + } + PICODBG_INFO_MSG(("\n")); + } + } +#endif + + break; + + + /* *********************************************************/ + /* process acc state: process items in headx and modify + * headx in place + */ + case SA_STEPSTATE_PROCESS_ACC: + /* ensure there is an item in inBuf */ + if (acph->headxLen > 0) { + /* we have a phrase in headx, cbuf (can be + single PUNC item), do accentuation and modify headx */ + if (PICO_OK != acphAccentuation(this, acph)) { + picoos_emRaiseException(this->common->em, + PICO_ERR_OTHER, NULL, NULL); + return PICODATA_PU_ERROR; + } + acph->procState = SA_STEPSTATE_FEED; + } else if (acph->headxLen == 0) { /* no items in inBuf */ + PICODBG_WARN(("no items in inBuf")); + acph->procState = SA_STEPSTATE_COLLECT; + return PICODATA_PU_BUSY; + } + break; + + + /* *********************************************************/ + /* feed state: copy item in internal outBuf to output charBuf */ + case SA_STEPSTATE_FEED: { + picoos_uint16 indupbound; + picoos_uint8 dopuoutfull; + + PICODBG_DEBUG(("put out items (bot, len): (%d, %d)", + acph->headxBottom, acph->headxLen)); + + indupbound = acph->headxBottom + acph->headxLen; + dopuoutfull = FALSE; + + if (acph->headxBottom == 0) { + /* construct first BOUND item in tmpbuf and put item */ + /* produce BOUND unless it is followed by a term/flush) */ + if (acph->headx[0].head.info1 + != PICODATA_ITEMINFO1_PUNC_FLUSH) { + if (!acphPutBoundItem(this, acph, + acph->headx[0].boundstrength, + acph->headx[0].boundtype, &dopuoutfull, + numBytesOutput)) { + if (dopuoutfull) { + PICODBG_DEBUG(("feeding overflow")); + return PICODATA_PU_OUT_FULL; + } else { + /* ERR-msg and exception done in acphPutBoundItem */ + return PICODATA_PU_ERROR; + } + } + } + } + + /* for all items in headx, cbuf */ + for (i = acph->headxBottom; i < indupbound; i++) { + + switch (acph->headx[i].head.type) { + case PICODATA_ITEM_PUNC: + /* if sentence end, put SEND bound */ + if ((acph->headx[i].head.info1 == + PICODATA_ITEMINFO1_PUNC_SENTEND) && + (i == (indupbound - 1))) { + /* construct and put BOUND item */ + if (!acphPutBoundItem(this, acph, + PICODATA_ITEMINFO1_BOUND_SEND, + PICODATA_ITEMINFO2_NA, + &dopuoutfull, numBytesOutput)) { + if (dopuoutfull) { + PICODBG_DEBUG(("feeding overflow")); + return PICODATA_PU_OUT_FULL; + } else { + /* ERR-msg and exception done + in acphPutBoundItem */ + return PICODATA_PU_ERROR; + } + } + } else if ((acph->headx[i].head.info1 == + PICODATA_ITEMINFO1_PUNC_FLUSH) && + (i == (indupbound - 1))) { + /* construct and put BOUND item */ + if (!acphPutBoundItem(this, acph, + PICODATA_ITEMINFO1_BOUND_TERM, + PICODATA_ITEMINFO2_NA, + &dopuoutfull, numBytesOutput)) { + if (dopuoutfull) { + PICODBG_DEBUG(("feeding overflow")); + return PICODATA_PU_OUT_FULL; + } else { + /* ERR-msg and exception done + in acphPutBoundItem */ + return PICODATA_PU_ERROR; + } + } + } + /* else, good-bye PUNC, not needed anymore */ + break; + default: + + /* PHR2/3 maybe existing, check and add + BOUND item now, if needed */ + if ((acph->headx[i].boundstrength == + PICODATA_ITEMINFO1_BOUND_PHR2) || + (acph->headx[i].boundstrength == + PICODATA_ITEMINFO1_BOUND_PHR3)) { + if (!acphPutBoundItem(this, acph, + acph->headx[i].boundstrength, + acph->headx[i].boundtype, + &dopuoutfull, numBytesOutput)) { + if (dopuoutfull) { + PICODBG_DEBUG(("feeding overflow")); + return PICODATA_PU_OUT_FULL; + } else { + /* ERR-msg and exception done + in acphPutBoundItem */ + return PICODATA_PU_ERROR; + } + } + } + + /* copy item unmodified */ + rv = picodata_put_itemparts(&(acph->headx[i].head), + &(acph->cbuf[acph->headx[i].cind]), + acph->headx[i].head.len, + acph->tmpbuf, PICODATA_MAX_ITEMSIZE, + &blen); + + rvP = picodata_cbPutItem(this->cbOut, acph->tmpbuf, + PICODATA_MAX_ITEMSIZE, &clen); + + *numBytesOutput += clen; + + PICODBG_DEBUG(("put item, status: %d", rvP)); + + if (rvP == PICO_OK) { + acph->headxBottom++; + acph->headxLen--; + } else if (rvP == PICO_EXC_BUF_OVERFLOW) { + /* try again next time, but PHR2/3 + bound already added if existing, + ensure it's not output a 2nd + time */ + PICODBG_DEBUG(("feeding overflow")); + acph->headx[i].boundstrength = 0; + return PICODATA_PU_OUT_FULL; + } else { + /* error, should never happen */ + PICODBG_ERROR(("untreated return value, rvP: %d", rvP)); + return PICODATA_PU_ERROR; + } + + PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG], + (picoos_uint8 *)"acph: ", + acph->tmpbuf, PICODATA_MAX_ITEMSIZE); + + break; + } /*switch*/ + } /*for*/ + + /* reset headx, cbuf */ + acph->headxBottom = 0; + acph->headxLen = 0; + acph->cbufLen = 0; + for (i = 0; i < PICOACPH_MAXNR_HEADX; i++) { + acph->headx[i].boundstrength = 0; + } + + /* reset collect state support variables */ + acph->inspaceok = TRUE; + acph->needsmoreitems = TRUE; + + acph->procState = SA_STEPSTATE_COLLECT; + return PICODATA_PU_BUSY; + break; + } + + default: + break; + } /* switch */ + + } /* while */ + + /* should be never reached */ + PICODBG_ERROR(("reached end of function")); + picoos_emRaiseException(this->common->em, PICO_ERR_OTHER, NULL, NULL); + return PICODATA_PU_ERROR; +} + +#ifdef __cplusplus +} +#endif + + +/* end */ diff --git a/pico/lib/picoacph.h b/pico/lib/picoacph.h new file mode 100644 index 0000000..266ab6e --- /dev/null +++ b/pico/lib/picoacph.h @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picoacph.h + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + + +/** + * @addtogroup picoacph + * +itemtype, iteminfo1, iteminfo2, content -> TYPE(INFO1,INFO2)content +in the following + +items input +=========== + +processed by sa (POS disambiguation): +- WORDGRAPH(POSes,NA)graph +- WORDINDEX(POSes,NA)POS|1ind1...POSN|indN +- CMD(PICODATA_ITEMINFO1_CMD_FLUSH,PICODATA_ITEMINFO2_NA) + +processed by sa (Phrasing, Accentuation): +- PUNC(PUNCtype,PUNCsubtype) + +unprocessed: +- all other item types are forwarded through the PU without modification: + CMD + + +minimal input size (before processing starts) +================== + +processing (POS disambiguation, g2p, lexind, phrasing, accentuation) +is possible with + +- one punctuation-phrase, consisting of a sequence (see below for + limits) of items terminated by a PUNC item. + +(possible but not implemented: as long as the internal buffer is +empty, non-processed item types can be processed immediately) + +Ensuring terminal PUNC item: +- when reading items from the external buffer a CMD(...FLUSH...) is + converted to a PUNC(...FLUSH...) item +- If needed, a PUNC(PHRASE) is artificially added to ensure a phrase + fits in the PUs memory and processing can start. + + +items processed and output +========================== + +precondition: +CMD(...FLUSH...) already converted to PUNC(...FLUSH...) and trailing +PUNC item enforced if necessary. + +---- +-# PROCESS_POSD: processing input WORDGRAPH or WORDINDEX items, after +POS disambiguation (POSes -> POS), results in a sequence of: + - + - WORDGRAPH(POS,NA)graph + - WORDINDEX(POS,NA)POS|ind + - + . +-# PROCESS_WPHO: then, after lex-index lookup and G2P in a +sequence of: + - WORDPHON(POS,NA)phon + +(phon containing primary and secondary word-level stress) + +---- +3. PROCESS_PHR: then, after processing these WORDPHON items, +together with the trailing PUNC item results in: + +-> BOUND(BOUNDstrength,BOUNDtype) + +being added in the sequence of WORDPHON (respectively inserted instead +of the PUNC). All PUNC, incl PUNC(...FLUSH...) now gone. + +---- +4. PROCESS_ACC: then, after processing the WORDPHON and BOUND items +results in: + +-> WORDPHON(POS,ACC)phon + +A postprocessing step of accentuation is hard-coded in the +accentuation module: In case the whole word does not have any stress +at all (primary or secondary or both) then do the following mapping: + + ACC0 nostress -> ACC0 + ACC1 nostress -> ACC3 + ACC2 nostress -> ACC3 + ACC3 nostress -> ACC3 + +---- +- POS + a single, unambiguous POS + +cf. picodata.h for +- ACC (sentence-level accent (aka prominence)) %d + - PICODATA_ACC0 + - PICODATA_ACC1 + - PICODATA_ACC2 (<- maybe mapped to ACC1, ie. no ACC2 in output) + - PICODATA_ACC3 + +- BOUNDstrength %d + - PICODATA_ITEMINFO1_BOUND_SBEG (at sentence start) + - PICODATA_ITEMINFO1_BOUND_SEND (at sentence end) + - PICODATA_ITEMINFO1_BOUND_TERM (replaces a flush) + - PICODATA_ITEMINFO1_BOUND_PHR1 (primary boundary) + - PICODATA_ITEMINFO1_BOUND_PHR2 (short break) + - PICODATA_ITEMINFO1_BOUND_PHR3 (secondary phrase boundary, no break) + - PICODATA_ITEMINFO1_BOUND_PHR0 (no break, not produced by sa, not existing + BOUND in item sequence equals PHR0 bound strength) + +- BOUNDtype (created in sa base on punctuation, indicates type of phrase + following the boundary) %d + - PICODATA_ITEMINFO2_BOUNDTYPE_P + - PICODATA_ITEMINFO2_BOUNDTYPE_T + - PICODATA_ITEMINFO2_BOUNDTYPE_Q + - PICODATA_ITEMINFO2_BOUNDTYPE_E + + +output sequence (without CMDs): + + = { BOUND(BOUND_SBEG,PHRASEtype) BOUND(BOUND_SEND,..)} BOUND(BOUND_TERM,..) + + = { BOUND(BOUND_PHR1|2|3,BOUNDtype) } + + = WORDPHON(POS,ACC)phon { WORDPHON(POS,ACC)phon } + +Done in later PU: mapping ACC & word-level stress to syllable accent value + - ACC0 prim -> 0 + - ACC1 prim -> 1 + - ACC2 prim -> 2 + - ACC3 prim -> 3 + - ACC0 sec -> 0 + - ACC1 sec -> 4 + - ACC2 sec -> 4 + - ACC3 sec -> 4 + +other limitations +================= + +- item size: header plus len=256 (valid for Pico in general) +- see defines below for max nr of items. Item heads plus ref. to contents + buffer are stored in array with fixed size elements. Two restrictions: + - MAXNR_HEADX (max nr elements==items in headx array) + - CONTENTSSIZE (max size of all contents together + */ + + +#ifndef PICOACPH_H_ +#define PICOACPH_H_ + +#include "picoos.h" +#include "picodata.h" +#include "picorsrc.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +/* nr item restriction: maximum number of extended item heads in headx */ +#define PICOACPH_MAXNR_HEADX 60 + +/* nr item restriction: maximum size of all item contents together in cont */ +#define PICOACPH_MAXSIZE_CBUF 7680 + + + +picodata_ProcessingUnit picoacph_newAccPhrUnit( + picoos_MemoryManager mm, + picoos_Common common, + picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, + picorsrc_Voice voice); + +#ifdef __cplusplus +} +#endif + +#endif /*PICOACPH_H_*/ diff --git a/pico/lib/picoapi.c b/pico/lib/picoapi.c new file mode 100644 index 0000000..589c0e0 --- /dev/null +++ b/pico/lib/picoapi.c @@ -0,0 +1,806 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picoapi.c + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + */ +#include "picodefs.h" +#include "picoos.h" +#include "picodbg.h" +#include "picorsrc.h" +#include "picoctrl.h" +#include "picoapi.h" +#include "picoapid.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ****************************************************************************/ +/* System-level API functions */ +/* ****************************************************************************/ + +#define MAGIC_MASK 0x5069636F /* Pico */ + +#define SET_MAGIC_NUMBER(sys) \ + (sys)->magic = ((picoos_uint32) (uintptr_t) (sys)) ^ MAGIC_MASK + +#define CHECK_MAGIC_NUMBER(sys) \ + ((sys)->magic == (((picoos_uint32) (uintptr_t) (sys)) ^ MAGIC_MASK)) + + + +/* *** Auxiliary routines (may also be called from picoextapi.c) **************/ + + +int is_valid_system_handle(pico_System system) +{ + return (system != NULL) && CHECK_MAGIC_NUMBER(system); +} + + +picoos_Common pico_sysGetCommon(pico_System this) +{ + if (this != NULL) { + return this->common; + } else { + return NULL; + } +} + + + +/* *** System initialization and termination functions ************************/ +pico_Status pico_initialize_priv( + void *memory, + const pico_Uint32 size, + pico_Int16 enableMemProt, + pico_System *system + ) +{ + pico_Status status = PICO_OK; + + PICODBG_INITIALIZE(PICODBG_LOG_LEVEL_INFO); + PICODBG_ENABLE_COLORS(0); + /*PICODBG_SET_OUTPUT_FORMAT((PICODBG_SHOW_LEVEL | PICODBG_SHOW_SRCNAME));*/ + + if (memory == NULL) { + status = PICO_ERR_NULLPTR_ACCESS; + } else if (size == 0) { + status = PICO_ERR_INVALID_ARGUMENT; + } else if (system == NULL) { + status = PICO_ERR_NULLPTR_ACCESS; + } else { + byte_ptr_t rest_mem; + picoos_objsize_t rest_mem_size; + pico_System sys; + picoos_MemoryManager sysMM; + picoos_ExceptionManager sysEM; + + sys = (pico_System) picoos_raw_malloc(memory, size, sizeof(pico_system_t), + &rest_mem, &rest_mem_size); + if (sys != NULL) { + sysMM = picoos_newMemoryManager(rest_mem, rest_mem_size, enableMemProt ? TRUE : FALSE); + if (sysMM != NULL) { + sysEM = picoos_newExceptionManager(sysMM); + sys->common = picoos_newCommon(sysMM); + sys->rm = picorsrc_newResourceManager(sysMM, sys->common); + if ((sysEM != NULL) && (sys->common != NULL) && (sys->rm != NULL)) { + sys->common->em = sysEM; + sys->common->mm = sysMM; + sys->engine = NULL; + + picorsrc_createDefaultResource(sys->rm /*,&defaultResource */); + + SET_MAGIC_NUMBER(sys); + status = PICO_OK; + } else { + status = PICO_EXC_OUT_OF_MEM; + } + } else { + status = PICO_EXC_OUT_OF_MEM; + } + } else { + status = PICO_EXC_OUT_OF_MEM; + } + *system = sys; + } + + if (status != PICO_OK) { + if (system != NULL) { + *system = NULL; + } + PICODBG_TERMINATE(); + } + + return status; +} +/** + * pico_initialize : initializes the pico system private memory + * @param memory : pointer to a free and already allocated memory area + * @param size : size of the memory area + * @param system : pointer to a pico_System struct + * @return PICO_OK : successful init, !PICO_OK : error on allocating private memory + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_initialize( + void *memory, + const pico_Uint32 size, + pico_System *system + ) +{ + return pico_initialize_priv(memory, size, /*enableMemProt*/ FALSE, system); +} + +/** + * pico_terminate : deallocates the pico system private memory + * @param system : pointer to a pico_System struct + * @return PICO_OK : successful de-init, !PICO_OK : error on de-allocating private memory + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_terminate( + pico_System *system + ) +{ + pico_Status status = PICO_OK; + + if ((system == NULL) || !is_valid_system_handle(*system)) { + status = PICO_ERR_INVALID_HANDLE; + } else { + pico_System sys = *system; + + /* close engine(s) */ + picoctrl_disposeEngine(sys->common->mm, sys->rm, &sys->engine); + + /* close all resources */ + picorsrc_disposeResourceManager(sys->common->mm, &sys->rm); + + sys->magic ^= 0xFFFEFDFC; + *system = NULL; + } + + PICODBG_TERMINATE(); + + return status; +} + + + +/* *** System status and error/warning message retrieval function *************/ + +/** + * pico_getSystemStatusMessage : Returns a description of the system status or errors + * @param system : pointer to a pico_System struct + * @param errCode : pico_System error code + * @param outMessage : memory area where to return a string + * @return PICO_OK : successful + * @return PICO_ERR_INVALID_HANDLE, PICO_ERR_NULLPTR_ACCESS : errors + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_getSystemStatusMessage( + pico_System system, + pico_Status errCode, + pico_Retstring outMessage + ) +{ + pico_Status status = PICO_OK; + + if (!is_valid_system_handle(system)) { + status = PICO_ERR_INVALID_HANDLE; + if (outMessage != NULL) { + picoos_strlcpy((picoos_char *) outMessage, (picoos_char *) "'system' not initialized", PICO_RETSTRINGSIZE); + } + } else if (outMessage == NULL) { + status = PICO_ERR_NULLPTR_ACCESS; + } else { + if (picoos_emGetExceptionCode(system->common->em) == PICO_OK) { + if (errCode == PICO_OK) { + picoos_strlcpy((picoos_char *) outMessage, (picoos_char *) "system ok", PICO_RETSTRINGSIZE); + } else { + /* exceptionManager was not informed yet; produce default message */ + picoos_setErrorMsg((picoos_char *) outMessage, PICO_RETSTRINGSIZE, errCode, NULL, NULL, NULL); + } + } else { + picoos_emGetExceptionMessage(system->common->em, (picoos_char *) outMessage, PICO_RETSTRINGSIZE); + } + } + + return status; +} + +/** + * pico_getSystemStatusMessage : Returns the number of warnings + * @param system : pointer to a pico_System struct + * @param *outNrOfWarnings : pointer to location to receive number of warnings + * @return PICO_OK : successful + * @return PICO_ERR_INVALID_HANDLE, PICO_ERR_NULLPTR_ACCESS : errors + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_getNrSystemWarnings( + pico_System system, + pico_Int32 *outNrOfWarnings + ) +{ + pico_Status status = PICO_OK; + + if (!is_valid_system_handle(system)) { + status = PICO_ERR_INVALID_HANDLE; + if (outNrOfWarnings != NULL) { + *outNrOfWarnings = 0; + } + } else if (outNrOfWarnings == NULL) { + status = PICO_ERR_NULLPTR_ACCESS; + } else { + *outNrOfWarnings = picoos_emGetNumOfWarnings(system->common->em); + } + + return status; +} + +/** + * pico_getSystemWarning : Returns a description of a warning + * @param system : pointer to a pico_System struct + * @param warningIndex : warning index + * @param *outCode : pointer to receive the warning code + * @param outMessage : pointer to receive the output message + * @return PICO_OK : successful + * @return PICO_ERR_INVALID_HANDLE, PICO_ERR_NULLPTR_ACCESS : errors + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_getSystemWarning( + pico_System system, + const pico_Int32 warningIndex, + pico_Status *outCode, + pico_Retstring outMessage + ) +{ + pico_Status status = PICO_OK; + + if (!is_valid_system_handle(system)) { + status = PICO_ERR_INVALID_HANDLE; + if (outMessage != NULL) { + picoos_strlcpy((picoos_char *) outMessage, (picoos_char *) "'system' not initialized", PICO_RETSTRINGSIZE); + } + } else if (warningIndex < 0) { + status = PICO_ERR_INDEX_OUT_OF_RANGE; + } else if ((outCode == NULL) || (outMessage == NULL)) { + status = PICO_ERR_NULLPTR_ACCESS; + } else { + *outCode = picoos_emGetWarningCode(system->common->em, warningIndex); + picoos_emGetWarningMessage(system->common->em, warningIndex, (picoos_char *) outMessage, (picoos_uint16) PICO_RETSTRINGSIZE); + } + + return status; +} + + + +/* *** Resource loading and unloading functions *******************************/ + +/** + * pico_loadResource : Loads a resource file into the Pico system + * @param system : pointer to a pico_System struct + * @param *lingwareFileName : lingware resource file name + * @param *outLingware : pointer to receive the loaded lingware resource memory area address + * @return PICO_OK : successful + * @return PICO_ERR_INVALID_HANDLE, PICO_ERR_NULLPTR_ACCESS : errors + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_loadResource( + pico_System system, + const pico_Char *lingwareFileName, + pico_Resource *outLingware + ) +{ + pico_Status status = PICO_OK; + + if (!is_valid_system_handle(system)) { + status = PICO_ERR_INVALID_HANDLE; + } else if ((lingwareFileName == NULL) || (outLingware == NULL)) { + status = PICO_ERR_NULLPTR_ACCESS; + } else { + PICODBG_DEBUG(("memory usage before resource loading")); + picoos_showMemUsage(system->common->mm, FALSE, TRUE); + picoos_emReset(system->common->em); + status = picorsrc_loadResource(system->rm, (picoos_char *) lingwareFileName, (picorsrc_Resource *) outLingware); + PICODBG_DEBUG(("memory used to load resource %s", lingwareFileName)); + picoos_showMemUsage(system->common->mm, TRUE, FALSE); + } + + return status; +} + +/** + * pico_unloadResource : unLoads a resource file from the Pico system + * @param system : pointer to a pico_System struct + * @param *inoutLingware : pointer to the loaded lingware resource memory area address + * @return PICO_OK : successful + * @return PICO_ERR_INVALID_HANDLE, PICO_ERR_NULLPTR_ACCESS : errors + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_unloadResource( + pico_System system, + pico_Resource *inoutLingware + ) +{ + pico_Status status = PICO_OK; + + if (!is_valid_system_handle(system)) { + status = PICO_ERR_INVALID_HANDLE; + } else if (inoutLingware == NULL) { + status = PICO_ERR_NULLPTR_ACCESS; + } else if (!picoctrl_isValidResourceHandle(*((picorsrc_Resource *) inoutLingware))) { + status = PICO_ERR_INVALID_HANDLE; + } else { + PICODBG_DEBUG(("memory usage before resource unloading")); + picoos_showMemUsage(system->common->mm, FALSE, TRUE); + picoos_emReset(system->common->em); + status = picorsrc_unloadResource(system->rm, (picorsrc_Resource *) inoutLingware); + PICODBG_DEBUG(("memory released by resource unloading")); + picoos_showMemUsage(system->common->mm, TRUE, FALSE); + } + + return status; +} + +/* *** Resource inspection functions *******************************/ +/** + * pico_getResourceName : Gets a resource name + * @param system : pointer to a pico_System struct + * @param resource : pointer to the loaded resource memory area address + * @param outName : pointer to the area to receuive the resource name + * @return PICO_OK : successful + * @return PICO_ERR_INVALID_HANDLE, PICO_ERR_NULLPTR_ACCESS : errors + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_getResourceName( + pico_System system, + pico_Resource resource, + pico_Retstring outName) { + + if (!is_valid_system_handle(system)) { + return PICO_ERR_INVALID_HANDLE; + } else if (NULL == outName) { + return PICO_ERR_NULLPTR_ACCESS; + } + return picorsrc_rsrcGetName((picorsrc_Resource)resource, (picoos_char *) outName, PICO_RETSTRINGSIZE); +} + + +/* *** Voice definition functions *********************************************/ + +/** + * pico_createVoiceDefinition : Creates a voice definition + * @param system : pointer to a pico_System struct + * @param *voiceName : pointer to the area to receive the voice definition + * @return PICO_OK : successful + * @return PICO_ERR_INVALID_HANDLE, PICO_ERR_NULLPTR_ACCESS : errors + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_createVoiceDefinition( + pico_System system, + const pico_Char *voiceName + ) +{ + pico_Status status = PICO_OK; + + if (!is_valid_system_handle(system)) { + status = PICO_ERR_INVALID_HANDLE; + } else if (voiceName == NULL) { + status = PICO_ERR_NULLPTR_ACCESS; + } else if (picoos_strlen((picoos_char *) voiceName) == 0) { + status = PICO_ERR_INVALID_ARGUMENT; + } else { + picoos_emReset(system->common->em); + status = picorsrc_createVoiceDefinition(system->rm, (picoos_char *) voiceName); + } + + return status; +} + +/** + * pico_addResourceToVoiceDefinition : Adds a mapping pair to a voice definition + * @param system : pointer to a pico_System struct + * @param *voiceName : pointer to the area containing the voice definition + * @param *resourceName : pointer to the area containing the resource name + * @return PICO_OK : successful + * @return PICO_ERR_INVALID_HANDLE, PICO_ERR_NULLPTR_ACCESS : errors + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_addResourceToVoiceDefinition( + pico_System system, + const pico_Char *voiceName, + const pico_Char *resourceName + ) +{ + pico_Status status = PICO_OK; + + if (!is_valid_system_handle(system)) { + status = PICO_ERR_INVALID_HANDLE; + } else if (voiceName == NULL) { + status = PICO_ERR_NULLPTR_ACCESS; + } else if (picoos_strlen((picoos_char *) voiceName) == 0) { + status = PICO_ERR_INVALID_ARGUMENT; + } else if (resourceName == NULL) { + status = PICO_ERR_NULLPTR_ACCESS; + } else if (picoos_strlen((picoos_char *) resourceName) == 0) { + status = PICO_ERR_INVALID_ARGUMENT; + } else { + picoos_emReset(system->common->em); + status = picorsrc_addResourceToVoiceDefinition(system->rm, (picoos_char *) voiceName, (picoos_char *) resourceName); + } + + return status; +} + +/** + * pico_releaseVoiceDefinition : Releases a voice definition + * @param system : pointer to a pico_System struct + * @param *voiceName : pointer to the area containing the voice definition + * @return PICO_OK : successful + * @return PICO_ERR_INVALID_HANDLE, PICO_ERR_NULLPTR_ACCESS : errors + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_releaseVoiceDefinition( + pico_System system, + const pico_Char *voiceName + ) +{ + pico_Status status = PICO_OK; + + if (!is_valid_system_handle(system)) { + status = PICO_ERR_INVALID_HANDLE; + } else if (voiceName == NULL) { + status = PICO_ERR_NULLPTR_ACCESS; + } else if (picoos_strlen((picoos_char *) voiceName) == 0) { + status = PICO_ERR_INVALID_ARGUMENT; + } else { + picoos_emReset(system->common->em); + status = picorsrc_releaseVoiceDefinition(system->rm, (picoos_char *) voiceName); + } + + return status; +} + + + +/* *** Engine creation and deletion functions *********************************/ + +/** + * pico_newEngine : Creates and initializes a new Pico engine + * @param system : pointer to a pico_System struct + * @param *voiceName : pointer to the area containing the voice definition + * @param *outEngine : pointer to the Pico engine handle + * @return PICO_OK : successful + * @return PICO_ERR_INVALID_HANDLE, PICO_ERR_NULLPTR_ACCESS : errors + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_newEngine( + pico_System system, + const pico_Char *voiceName, + pico_Engine *outEngine + ) +{ + pico_Status status = PICO_OK; + + PICODBG_DEBUG(("creating engine for voice '%s'", (picoos_char *) voiceName)); + + if (!is_valid_system_handle(system)) { + status = PICO_ERR_INVALID_HANDLE; + } else if (voiceName == NULL) { + status = PICO_ERR_NULLPTR_ACCESS; + } else if (picoos_strlen((picoos_char *) voiceName) == 0) { + status = PICO_ERR_INVALID_ARGUMENT; + } else if (outEngine == NULL) { + status = PICO_ERR_NULLPTR_ACCESS; + } else { + picoos_emReset(system->common->em); + if (system->engine == NULL) { + *outEngine = (pico_Engine) picoctrl_newEngine(system->common->mm, system->rm, voiceName); + if (*outEngine != NULL) { + system->engine = (picoctrl_Engine) *outEngine; + } else { + status = picoos_emRaiseException(system->common->em, PICO_EXC_OUT_OF_MEM, + (picoos_char *) "out of memory creating new engine", NULL); + } + } else { + status = picoos_emRaiseException(system->common->em, PICO_EXC_MAX_NUM_EXCEED, + NULL, (picoos_char *) "no more than %i engines", 1); + } + } + + return status; +} + +/** + * pico_disposeEngine : Disposes a Pico engine + * @param system : pointer to a pico_System struct + * @param *inoutEngine : pointer to the Pico engine handle + * @return PICO_OK : successful + * @return PICO_ERR_INVALID_HANDLE, PICO_ERR_NULLPTR_ACCESS : errors + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_disposeEngine( + pico_System system, + pico_Engine *inoutEngine + ) +{ + pico_Status status = PICO_OK; + + if (!is_valid_system_handle(system)) { + status = PICO_ERR_INVALID_HANDLE; + } else if (inoutEngine == NULL) { + status = PICO_ERR_NULLPTR_ACCESS; + } else if (!picoctrl_isValidEngineHandle(*((picoctrl_Engine *) inoutEngine))) { + status = PICO_ERR_INVALID_HANDLE; + } else { + picoos_emReset(system->common->em); + picoctrl_disposeEngine(system->common->mm, system->rm, (picoctrl_Engine *) inoutEngine); + system->engine = NULL; + status = picoos_emGetExceptionCode(system->common->em); + } + + return status; +} + + + +/* ****************************************************************************/ +/* Engine-level API functions */ +/* ****************************************************************************/ + +/** + * pico_putTextUtf8 : Puts UTF8 text into Pico text input buffer + * @param engine : pointer to a Pico engine handle + * @param *text : pointer to the text buffer + * @param textSize : text buffer size + * @param *bytesPut : pointer to variable to receive the number of bytes put + * @return PICO_OK : successful + * @return PICO_ERR_INVALID_HANDLE, PICO_ERR_NULLPTR_ACCESS : errors + * @callgraph + * @callergraph + */ +PICO_FUNC pico_putTextUtf8( + pico_Engine engine, + const pico_Char *text, + const pico_Int16 textSize, + pico_Int16 *bytesPut) +{ + pico_Status status = PICO_OK; + + if (!picoctrl_isValidEngineHandle((picoctrl_Engine) engine)) { + status = PICO_ERR_INVALID_HANDLE; + } else if (text == NULL) { + status = PICO_ERR_NULLPTR_ACCESS; + } else if (textSize < 0) { + status = PICO_ERR_INVALID_ARGUMENT; + } else if (bytesPut == NULL) { + status = PICO_ERR_NULLPTR_ACCESS; + } else { + picoctrl_engResetExceptionManager((picoctrl_Engine) engine); + status = picoctrl_engFeedText((picoctrl_Engine) engine, (picoos_char *)text, textSize, bytesPut); + } + + return status; +} + +/** + * pico_getData : Gets speech data from the engine. + * @param engine : pointer to a Pico engine handle + * @param *buffer : pointer to output buffer + * @param bufferSize : out buffer size + * @param *bytesReceived : pointer to a variable to receive the number of bytes received + * @param *outDataType : pointer to a variable to receive the type of buffer received + * @return PICO_OK : successful + * @return PICO_ERR_INVALID_HANDLE, PICO_ERR_NULLPTR_ACCESS : errors + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_getData( + pico_Engine engine, + void *buffer, + const pico_Int16 bufferSize, + pico_Int16 *bytesReceived, + pico_Int16 *outDataType + ) +{ + pico_Status status = PICO_OK; + + if (!picoctrl_isValidEngineHandle((picoctrl_Engine) engine)) { + status = PICO_STEP_ERROR; + } else if (buffer == NULL) { + status = PICO_STEP_ERROR; + } else if (bufferSize < 0) { + status = PICO_STEP_ERROR; + } else if (bytesReceived == NULL) { + status = PICO_STEP_ERROR; + } else { + picoctrl_engResetExceptionManager((picoctrl_Engine) engine); + status = picoctrl_engFetchOutputItemBytes((picoctrl_Engine) engine, (picoos_char *)buffer, bufferSize, bytesReceived); + if ((status != PICO_STEP_IDLE) && (status != PICO_STEP_BUSY)) { + status = PICO_STEP_ERROR; + } + } + + *outDataType = PICO_DATA_PCM_16BIT; + return status; +} + +/** + * pico_resetEngine : Resets the engine + * @param engine : pointer to a Pico engine handle + * @param resetMode : reset mode; one of PICO_RESET_FULL or PICO_RESET_SOFT + * @return PICO_OK : successful + * @return PICO_ERR_INVALID_HANDLE, PICO_ERR_NULLPTR_ACCESS : errors + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_resetEngine( + pico_Engine engine, + pico_Int32 resetMode) +{ + pico_Status status = PICO_OK; + + if (!picoctrl_isValidEngineHandle((picoctrl_Engine) engine)) { + status = PICO_ERR_INVALID_HANDLE; + } else { + picoctrl_engResetExceptionManager((picoctrl_Engine) engine); + + resetMode = (PICO_RESET_SOFT == resetMode) ? PICO_RESET_SOFT : PICO_RESET_FULL; + + status = picoctrl_engReset((picoctrl_Engine) engine, (picoos_int32)resetMode); + } + + return status; +} + +/** + * pico_getEngineStatusMessage : Returns the engine status or error description + * @param engine : pointer to a Pico engine handle + * @param errCode : error code + * @param outMessage : pointer to a memory area to receive the output message + * @return PICO_OK : successful + * @return PICO_ERR_INVALID_HANDLE, PICO_ERR_NULLPTR_ACCESS : errors + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_getEngineStatusMessage( + pico_Engine engine, + pico_Status errCode, + pico_Retstring outMessage + ) +{ + pico_Status status = PICO_OK; + + PICODBG_DEBUG(("got error code %i", errCode)); + + if (!picoctrl_isValidEngineHandle((picoctrl_Engine) engine)) { + status = PICO_ERR_INVALID_HANDLE; + if (outMessage != NULL) { + picoos_strlcpy((picoos_char *) outMessage, (picoos_char *) "'engine' not initialized", PICO_RETSTRINGSIZE); + } + } else if (outMessage == NULL) { + status = PICO_ERR_NULLPTR_ACCESS; + } else { + picoos_Common common = picoctrl_engGetCommon((picoctrl_Engine) engine); + if (picoos_emGetExceptionCode(common->em) == PICO_OK) { + if (errCode == PICO_OK) { + picoos_strlcpy((picoos_char *) outMessage, (picoos_char *) "engine ok", PICO_RETSTRINGSIZE); + } else { + /* exceptionManager was not informed yet; produce default message */ + picoos_setErrorMsg((picoos_char *) outMessage, PICO_RETSTRINGSIZE, errCode, NULL, NULL, NULL); + } + } else { + picoos_emGetExceptionMessage(common->em, (picoos_char *) outMessage, PICO_RETSTRINGSIZE); + } + } + + return status; +} + +/** + * pico_getNrEngineWarnings : Returns the number of warnings + * @param engine : pointer to a Pico engine handle + * @param *outNrOfWarnings: pointer to a variable to receive the number of warnings + * @return PICO_OK : successful + * @return PICO_ERR_INVALID_HANDLE, PICO_ERR_NULLPTR_ACCESS : errors + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_getNrEngineWarnings( + pico_Engine engine, + pico_Int32 *outNrOfWarnings + ) +{ + pico_Status status = PICO_OK; + + if (!picoctrl_isValidEngineHandle((picoctrl_Engine) engine)) { + status = PICO_ERR_INVALID_HANDLE; + if (outNrOfWarnings != NULL) { + *outNrOfWarnings = 0; + } + } else if (outNrOfWarnings == NULL) { + status = PICO_ERR_NULLPTR_ACCESS; + } else { + picoos_Common common = picoctrl_engGetCommon((picoctrl_Engine) engine); + *outNrOfWarnings = picoos_emGetNumOfWarnings(common->em); + } + + return status; +} + +/** + * pico_getEngineWarning : Returns a description of a warning + * @param engine : pointer to a Pico engine handle + * @param warningIndex : warning index + * @param *outCode: pointer to a variable to receive the warning code + * @param outMessage: pointer to a memory area to receive the warning description + * @return PICO_OK : successful + * @return PICO_ERR_INVALID_HANDLE, PICO_ERR_NULLPTR_ACCESS : errors + * @callgraph + * @callergraph +*/ +PICO_FUNC pico_getEngineWarning( + pico_Engine engine, + const pico_Int32 warningIndex, + pico_Status *outCode, + pico_Retstring outMessage + ) +{ + pico_Status status = PICO_OK; + + if (!picoctrl_isValidEngineHandle((picoctrl_Engine) engine)) { + status = PICO_ERR_INVALID_HANDLE; + if (outMessage != NULL) { + picoos_strlcpy((picoos_char *) outMessage, (picoos_char *) "'engine' not initialized", PICO_RETSTRINGSIZE); + } + } else if (warningIndex < 0) { + status = PICO_ERR_INDEX_OUT_OF_RANGE; + } else if ((outCode == NULL) || (outMessage == NULL)) { + status = PICO_ERR_NULLPTR_ACCESS; + } else { + picoos_Common common = picoctrl_engGetCommon((picoctrl_Engine) engine); + *outCode = picoos_emGetWarningCode(common->em, warningIndex); + picoos_emGetWarningMessage(common->em, warningIndex, (picoos_char *) outMessage, (picoos_uint16) PICO_RETSTRINGSIZE); + } + + return status; +} + +#ifdef __cplusplus +} +#endif + + +/* end */ diff --git a/pico/lib/picoapi.h b/pico/lib/picoapi.h new file mode 100644 index 0000000..aa60358 --- /dev/null +++ b/pico/lib/picoapi.h @@ -0,0 +1,472 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picoapi.h + * + * SVOX Pico application programming interface + * (SVOX Pico version 1.0 and later) + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + */ + + +/** + * @addtogroup picoapi + * +@b Basic_Concepts + +@e SVOX_Pico_System + +The SVOX Pico 'system' is the entity that manages data common to all +SVOX Pico engines, e.g. linguistic data needed to do text-to-speech +(TTS) synthesis, license key, etc. All API functions on the Pico +system level take a 'pico_System' handle as the first parameter. + +@e SVOX_Pico_Engine + +A SVOX Pico 'engine' provides the functions needed to perform actual +synthesis. Currently there can be only one engine instance at a time +(concurrent engines will be possible in the future). All API functions +at the engine level take a 'pico_Engine' handle as the first +parameter. + +@e SVOX_Pico_Resource + +A SVOX Pico 'resource' denotes all the language- and speaker-dependent +data needed to do TTS synthesis. In the following, the term 'resource' +may be used interchangeably with the term 'lingware'. A resource file +contains a set of knowledge bases for an entire TTS voice or parts of +it. + + +@b Basic_Usage + +In its most basic form, an application must call the following +functions in order to perform TTS synthesis: + + - pico_initialize + - pico_loadResource + - pico_createVoiceDefinition + - pico_addResourceToVoiceDefinition + - pico_newEngine + - pico_putTextUtf8 + - pico_getData (several times) + - pico_disposeEngine + - pico_releaseVoiceDefinition + - pico_unloadResource + - pico_terminate + +It is possible to repeatedly run the above sequence, i.e., the SVOX +Pico system may be initialized and terminated multiple times. This may +be useful in applications that need TTS functionality only from time +to time. + + +@b Conventions + +@e Function_arguments + +All arguments that only return values are marked by a leading 'out...' +in their name. All arguments that are used as input and output values +are marked by a leading 'inout...'. All other arguments are read-only +(input) arguments. + +@e Error_handling + +All API functions return a status code which is one of the status +constants defined in picodefs.h. In case of an error, a more detailed +description of the status can be retrieved by calling function +'pico_getSystemStatusMessage' (or 'pico_getEngineStatusMessage' +if the error happened on the SVOX Pico engine level). + +Unlike errors, warnings do not prevent an API function from performing +its function, but output might not be as intended. Functions +'pico_getNrSystemWarnings' and 'pico_getNrEngineWarnings' respectively +can be used to determine whether an API function caused any +warnings. Details about warnings can be retrieved by calling +'pico_getSystemWarning' and 'pico_getEngineWarning' respectively. + +*/ + + + +#ifndef PICOAPI_H_ +#define PICOAPI_H_ + + + +#include "picodefs.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +#ifdef _WIN32 +# define PICO_EXPORT __declspec( dllexport ) +#else +# define PICO_EXPORT extern +#endif + +#define PICO_FUNC PICO_EXPORT pico_Status + + + +/* ********************************************************************/ +/* PICO data types */ +/* ********************************************************************/ + +/* Handle types (opaque) for Pico system, resource, engine ************/ + +typedef struct pico_system *pico_System; +typedef struct pico_resource *pico_Resource; +typedef struct pico_engine *pico_Engine; + + +/* Signed/unsigned integer data types *********************************/ + +#define PICO_INT16_MAX 32767 +#define PICO_UINT16_MAX 0xffff +#define PICO_INT32_MAX 2147483647 +#define PICO_UINT32_MAX 0xffffffff + +#include + +#if (SHRT_MAX == PICO_INT16_MAX) +typedef short pico_Int16; +#else +#error "platform not supported" +#endif + +#if (USHRT_MAX == PICO_UINT16_MAX) +typedef unsigned short pico_Uint16; +#else +#error "platform not supported" +#endif + +#if (INT_MAX == PICO_INT32_MAX) +typedef int pico_Int32; +#else +#error "platform not supported" +#endif + +#if (UINT_MAX == PICO_UINT32_MAX) +typedef unsigned int pico_Uint32; +#else +#error "platform not supported" +#endif + + +/* Char data type *****************************************************/ + +typedef unsigned char pico_Char; + + +/* String type to be used when ASCII string values are returned *******/ + +#define PICO_RETSTRINGSIZE 200 /* maximum length of returned strings */ + +typedef char pico_Retstring[PICO_RETSTRINGSIZE]; + + + +/* ********************************************************************/ +/* System-level API functions */ +/* ********************************************************************/ + +/* System initialization and termination functions ********************/ + +/** + Initializes the Pico system and returns its handle in 'outSystem'. + 'memory' and 'size' define the location and maximum size of memory + in number of bytes that the Pico system will use. The minimum size + required depends on the number of engines and configurations of + lingware to be used. No additional memory will be allocated by the + Pico system. This function must be called before any other API + function is called. It may only be called once (e.g. at application + startup), unless a call to 'pico_terminate'. +*/ +PICO_FUNC pico_initialize( + void *memory, + const pico_Uint32 size, + pico_System *outSystem + ); + +/** + Terminates the Pico system. Lingware resources still being loaded + are unloaded automatically. The memory area provided to Pico in + 'pico_initialize' is released. The system handle becomes + invalid. It is not allowed to call this function as long as Pico + engine instances are existing. No API function may be called after + this function, except for 'pico_initialize', which reinitializes + the system. +*/ +PICO_FUNC pico_terminate( + pico_System *system + ); + + +/* System status and error/warning message retrieval ******************/ + +/** + Returns in 'outMessage' a description of the system status or of an + error that occurred with the most recently called system-level API + function. +*/ +PICO_FUNC pico_getSystemStatusMessage( + pico_System system, + pico_Status errCode, + pico_Retstring outMessage + ); + +/** + Returns in 'outNrOfWarnings' the number of warnings that occurred + with the most recently called system-level API function. +*/ +PICO_FUNC pico_getNrSystemWarnings( + pico_System system, + pico_Int32 *outNrOfWarnings + ); + +/** + Returns in 'outMessage' a description of a warning that occurred + with the most recently called system-level API function. + 'warningIndex' must be in the range 0..N-1 where N is the number of + warnings returned by 'pico_getNrSystemWarnings'. 'outCode' returns + the warning as an integer code (cf. PICO_WARN_*). +*/ +PICO_FUNC pico_getSystemWarning( + pico_System system, + const pico_Int32 warningIndex, + pico_Status *outCode, + pico_Retstring outMessage + ); + + +/* Resource loading and unloading functions ***************************/ + +/** + Loads a resource file into the Pico system. The number of resource + files loaded in parallel is limited by PICO_MAX_NUM_RESOURCES. + Loading of a resource file may be done at any time (even in + parallel to a running engine doing TTS synthesis), but with the + general restriction that functions taking a system handle as their + first argument must be called in a mutually exclusive fashion. The + loaded resource will be available only to engines started after the + resource is fully loaded, i.e., not to engines currently + running. +*/ +PICO_FUNC pico_loadResource( + pico_System system, + const pico_Char *resourceFileName, + pico_Resource *outResource + ); + +/** + Unloads a resource file from the Pico system. If no engine uses the + resource file, the resource is removed immediately and its + associated internal memory is released, otherwise + PICO_EXC_RESOURCE_BUSY is returned. +*/ +PICO_FUNC pico_unloadResource( + pico_System system, + pico_Resource *inoutResource + ); + +/* *** Resource inspection functions *******************************/ + +/** + Gets the unique resource name of a loaded resource +*/ +PICO_FUNC pico_getResourceName( + pico_System system, + pico_Resource resource, + pico_Retstring outName); + + +/* Voice definition ***************************************************/ + +/** + Creates a voice definition. Resources must be added to the created + voice with 'pico_addResourceToVoiceDefinition' before using the + voice in 'pico_newEngine'. It is an error to create a voice + definition with a previously defined voice name. In that case use + 'pico_releaseVoiceName' first. +*/ +PICO_FUNC pico_createVoiceDefinition( + pico_System system, + const pico_Char *voiceName + ); + +/** + Adds a mapping pair ('voiceName', 'resourceName') to the voice + definition. Multiple mapping pairs can added to a voice defintion. + When calling 'pico_newEngine' with 'voiceName', the corresponding + resources from the mappings will be used with that engine. */ + +PICO_FUNC pico_addResourceToVoiceDefinition( + pico_System system, + const pico_Char *voiceName, + const pico_Char *resourceName + ); + + +/** + Releases the voice definition 'voiceName'. + +*/ +PICO_FUNC pico_releaseVoiceDefinition( + pico_System system, + const pico_Char *voiceName + ); + + +/* Engine creation and deletion functions *****************************/ + +/** + Creates and initializes a new Pico engine instance and returns its + handle in 'outEngine'. Only one instance per system is currently + possible. +*/ +PICO_FUNC pico_newEngine( + pico_System system, + const pico_Char *voiceName, + pico_Engine *outEngine + ); + + +/** + Disposes a Pico engine and releases all memory it occupied. The + engine handle becomes invalid. +*/ +PICO_FUNC pico_disposeEngine( + pico_System system, + pico_Engine *inoutEngine + ); + + + +/* ********************************************************************/ +/* Engine-level API functions */ +/* ********************************************************************/ + +/** + Puts text 'text' encoded in UTF8 into the Pico text input buffer. + 'textSize' is the maximum size in number of bytes accessible in + 'text'. The input text may also contain text-input commands to + change, for example, speed or pitch of the resulting speech + output. The number of bytes actually copied to the Pico text input + buffer is returned in 'outBytesPut'. Sentence ends are + automatically detected. '\0' characters may be embedded in 'text' + to finish text input or separate independently to be synthesized + text parts from each other. Repeatedly calling 'pico_getData' will + result in the content of the text input buffer to be synthesized + (up to the last sentence end or '\0' character detected). To empty + the internal buffers without finishing synthesis, use the function + 'pico_resetEngine'. +*/ +PICO_FUNC pico_putTextUtf8( + pico_Engine engine, + const pico_Char *text, + const pico_Int16 textSize, + pico_Int16 *outBytesPut + ); + +/** + Gets speech data from the engine. Every time this function is + called, the engine performs, within a short time slot, a small + amount of processing its input text, and then gives control back to + the calling application. Ie. after calling 'pico_putTextUtf8' + (incl. a final embedded '\0'), this function needs to be called + repeatedly till 'outBytesReceived' bytes are returned in + 'outBuffer'. The type of data returned in 'outBuffer' (e.g. 8 or 16 + bit PCM samples) is returned in 'outDataType' and depends on the + lingware resources. Possible 'outDataType' values are listed in + picodefs.h (PICO_DATA_*). + This function returns PICO_STEP_BUSY while processing input and + producing speech output. Once all data is returned and there is no + more input text available in the Pico text input buffer, + PICO_STEP_IDLE is returned. All other function return values + indicate a system error. +*/ +PICO_FUNC pico_getData( + pico_Engine engine, + void *outBuffer, + const pico_Int16 bufferSize, + pico_Int16 *outBytesReceived, + pico_Int16 *outDataType + ); + +/** + Resets the engine and clears all engine-internal buffers, in + particular text input and signal data output buffers. + 'resetMode' is one of 'PICO_RESET_SOFT', to be used to flush the engine, + or 'PICO_RESET_FULL', to reset the engine after an engine error. +*/ +PICO_FUNC pico_resetEngine( + pico_Engine engine, + pico_Int32 resetMode +); + + +/* Engine status and error/warning message retrieval ******************/ + +/** + Returns in 'outMessage' a description of the engine status or of an + error that occurred with the most recently called engine-level API + function. +*/ +PICO_FUNC pico_getEngineStatusMessage( + pico_Engine engine, + pico_Status errCode, + pico_Retstring outMessage + ); + +/** + Returns in 'outNrOfWarnings' the number of warnings that occurred + with the most recently called engine-level API function. +*/ +PICO_FUNC pico_getNrEngineWarnings( + pico_Engine engine, + pico_Int32 *outNrOfWarnings + ); + +/** + Returns in 'outMessage' a description of a warning that occurred + with the most recently called engine-level API function. + 'warningIndex' must be in the range 0..N-1 where N is the number of + warnings returned by 'pico_getNrEngineWarnings'. 'outCode' returns + the warning as an integer code (cf. PICO_WARN_*). +*/ +PICO_FUNC pico_getEngineWarning( + pico_Engine engine, + const pico_Int32 warningIndex, + pico_Status *outCode, + pico_Retstring outMessage + ); + +#ifdef __cplusplus +} +#endif + +#endif /*PICOAPI_H_*/ diff --git a/pico/lib/picoapid.h b/pico/lib/picoapid.h new file mode 100644 index 0000000..ef62701 --- /dev/null +++ b/pico/lib/picoapid.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picoapid.h + * + * Pico api definitions commonly used by picoapi and picoapiext + * + * This header file must be part of the runtime-only pico system and therefore + * must not include picoapiext.h! + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#ifndef PICOAPID_H_ +#define PICOAPID_H_ + +#include "picodefs.h" +#include "picoapi.h" +#include "picoos.h" +#include "picorsrc.h" +#include "picoctrl.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* Pico system descriptor */ +typedef struct pico_system { + picoos_uint32 magic; /* magic number used to validate handles */ + picoos_Common common; + picorsrc_ResourceManager rm; + picoctrl_Engine engine; +} pico_system_t; + + +/* declared in picoapi.c */ +extern int is_valid_system_handle(pico_System system); +extern picoos_Common pico_sysGetCommon(pico_System this); + + +#if 0 +{ +#endif +#ifdef __cplusplus +} +#endif + +#endif /* PICOAPID_H_ */ diff --git a/pico/lib/picobase.c b/pico/lib/picobase.c new file mode 100644 index 0000000..9246551 --- /dev/null +++ b/pico/lib/picobase.c @@ -0,0 +1,1243 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picobase.c + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include "picoos.h" +#include "picodbg.h" +#include "picodefs.h" +#include "picobase.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +/** + * @addtogroup picobase + * + * @b Unicode_UTF8_functions + * + * UTF8 + * scalar value 1st Byte 2nd Byte 3rd Byte 4th Byte + * 00000000 0xxxxxxx 0xxxxxxx + * 00000yyy yyxxxxxx 110yyyyy 10xxxxxx + * zzzzyyyy yyxxxxxx 1110zzzz 10yyyyyy 10xxxxxx + * 000uuuuu zzzzyyyy yyxxxxx 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx + * +*/ +picoos_int32 picobase_utf8_length(const picoos_uint8 *utf8str, + const picoos_uint16 maxlen) { + + picoos_uint16 i; + picoos_uint16 len; + picoos_uint8 follow; + picoos_uint8 ok; + + ok = TRUE; + i = 0; + len = 0; + follow = 0; + while (ok && (i < maxlen) && (utf8str[i] != '\000')) { + if (follow > 0) { + if ((utf8str[i] >= (picoos_uint8)'\200') && + (utf8str[i] < (picoos_uint8)'\300')) { + follow--; + } else { + ok = FALSE; + } + } else if (utf8str[i] < (picoos_uint8)'\200') { + len++; + } else if (utf8str[i] >= (picoos_uint8)'\370') { + ok = FALSE; + } else if (utf8str[i] >= (picoos_uint8)'\360') { + follow = 3; + len++; + } else if (utf8str[i] >= (picoos_uint8)'\340') { + follow = 2; + len++; + } else if (utf8str[i] >= (picoos_uint8)'\300') { + follow = 1; + len++; + } else { + ok = FALSE; + } + i++; + } + if (ok) { + return len; + } else { + return -1; + } +} + + +static picoos_uint32 base_utf32_lowercase (picoos_uint32 utf32) +{ + + picoos_uint32 lc; + + lc = utf32; + if (((utf32 >= 65313) && (utf32 <= 65338))) { + lc = (utf32 + 32); + } else if (((utf32 >= 66560) && (utf32 <= 66599))) { + lc = (utf32 + 40); + } else if (((utf32 >= 7680) && (utf32 <= 9423))) { + switch (utf32) { + case 7680: case 7681: case 7682: case 7683: case 7684: case 7685: case 7686: case 7687: case 7688: case 7689: + case 7690: case 7691: case 7692: case 7693: case 7694: case 7695: case 7696: case 7697: case 7698: case 7699: case 7700: case 7701: + case 7702: case 7703: case 7704: case 7705: case 7706: case 7707: case 7708: case 7709: case 7710: case 7711: case 7712: case 7713: + case 7714: case 7715: case 7716: case 7717: case 7718: case 7719: case 7720: case 7721: case 7722: case 7723: case 7724: case 7725: + case 7726: case 7727: case 7728: case 7729: case 7730: case 7731: case 7732: case 7733: case 7734: case 7735: case 7736: case 7737: + case 7738: case 7739: case 7740: case 7741: case 7742: case 7743: case 7744: case 7745: case 7746: case 7747: case 7748: case 7749: + case 7750: case 7751: case 7752: case 7753: case 7754: case 7755: case 7756: case 7757: case 7758: case 7759: case 7760: case 7761: + case 7762: case 7763: case 7764: case 7765: case 7766: case 7767: case 7768: case 7769: case 7770: case 7771: case 7772: case 7773: + case 7774: case 7775: case 7776: case 7777: case 7778: case 7779: case 7780: case 7781: case 7782: case 7783: case 7784: case 7785: + case 7786: case 7787: case 7788: case 7789: case 7790: case 7791: case 7792: case 7793: case 7794: case 7795: case 7796: case 7797: + case 7798: case 7799: case 7800: case 7801: case 7802: case 7803: case 7804: case 7805: case 7806: case 7807: case 7808: case 7809: + case 7810: case 7811: case 7812: case 7813: case 7814: case 7815: case 7816: case 7817: case 7818: case 7819: case 7820: case 7821: + case 7822: case 7823: case 7824: case 7825: case 7826: case 7827: case 7828: case 7840: case 7841: case 7842: case 7843: + case 7844: case 7845: case 7846: case 7847: case 7848: case 7849: case 7850: case 7851: case 7852: case 7853: case 7854: case 7855: + case 7856: case 7857: case 7858: case 7859: case 7860: case 7861: case 7862: case 7863: case 7864: case 7865: case 7866: case 7867: + case 7868: case 7869: case 7870: case 7871: case 7872: case 7873: case 7874: case 7875: case 7876: case 7877: case 7878: case 7879: + case 7880: case 7881: case 7882: case 7883: case 7884: case 7885: case 7886: case 7887: case 7888: case 7889: case 7890: case 7891: + case 7892: case 7893: case 7894: case 7895: case 7896: case 7897: case 7898: case 7899: case 7900: case 7901: case 7902: case 7903: + case 7904: case 7905: case 7906: case 7907: case 7908: case 7909: case 7910: case 7911: case 7912: case 7913: case 7914: case 7915: + case 7916: case 7917: case 7918: case 7919: case 7920: case 7921: case 7922: case 7923: case 7924: case 7925: case 7926: case 7927: + case 7928: + if ( !(((utf32) % 2 == 1))) { + lc = (utf32 + 1); + } + break; + case 7944: case 7945: case 7946: case 7947: case 7948: case 7949: case 7950: case 7951: case 7960: + case 7961: case 7962: case 7963: case 7964: case 7965: case 7976: case 7977: case 7978: case 7979: case 7980: case 7981: + case 7982: case 7983: case 7992: case 7993: case 7994: case 7995: case 7996: case 7997: case 7998: case 7999: + case 8008: case 8009: case 8010: case 8011: case 8012: case 8013: case 8040: case 8041: case 8042: case 8043: case 8044: + case 8045: case 8046: case 8047: case 8072: case 8073: case 8074: case 8075: case 8076: case 8077: case 8078: case 8079: + case 8088: case 8089: case 8090: case 8091: case 8092: case 8093: case 8094: case 8095: case 8104: case 8105: + case 8106: case 8107: case 8108: case 8109: case 8110: case 8111: + lc = (utf32 - 8); + break; + case 8025: case 8026: case 8027: case 8028: case 8029: case 8030: case 8031: + if (((utf32) % 2 == 1)) { + lc = (utf32 - 8); + } + break; + case 8544: case 8545: case 8546: case 8547: case 8548: case 8549: case 8550: case 8551: case 8552: case 8553: + case 8554: case 8555: case 8556: case 8557: case 8558: case 8559: + lc = (utf32 + 16); + break; + case 9398: case 9399: case 9400: case 9401: case 9402: case 9403: case 9404: case 9405: case 9406: case 9407: + case 9408: case 9409: case 9410: case 9411: case 9412: case 9413: case 9414: case 9415: case 9416: case 9417: case 9418: case 9419: + case 9420: case 9421: case 9422: case 9423: + lc = (utf32 + 26); + break; + case 8120: + lc = 8112; + break; + case 8121: + lc = 8113; + break; + case 8122: + lc = 8048; + break; + case 8123: + lc = 8049; + break; + case 8124: + lc = 8115; + break; + case 8136: + lc = 8050; + break; + case 8137: + lc = 8051; + break; + case 8138: + lc = 8052; + break; + case 8139: + lc = 8053; + break; + case 8140: + lc = 8131; + break; + case 8152: + lc = 8144; + break; + case 8153: + lc = 8145; + break; + case 8154: + lc = 8054; + break; + case 8155: + lc = 8055; + break; + case 8168: + lc = 8160; + break; + case 8169: + lc = 8161; + break; + case 8170: + lc = 8058; + break; + case 8171: + lc = 8059; + break; + case 8172: + lc = 8165; + break; + case 8184: + lc = 8056; + break; + case 8185: + lc = 8057; + break; + case 8186: + lc = 8060; + break; + case 8187: + lc = 8061; + break; + case 8188: + lc = 8179; + break; + case 8486: + lc = 969; + break; + case 8490: + lc = 107; + break; + case 8491: + lc = 229; + break; + default: + break; + } + } else { + switch (utf32) { + case 65: case 66: case 67: case 68: case 69: case 70: case 71: case 72: case 73: case 74: + case 75: case 76: case 77: case 78: case 79: case 80: case 81: case 82: case 83: case 84: case 85: case 86: + case 87: case 88: case 89: case 90: case 192: case 193: case 194: case 195: case 196: case 197: case 198: + case 199: case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 207: case 208: case 209: case 210: + case 211: case 212: case 213: case 214: case 216: case 217: case 218: case 219: case 220: case 221: case 222: + case 913: case 914: case 915: case 916: case 917: case 918: case 919: case 920: case 921: case 922: case 923: + case 924: case 925: case 926: case 927: case 928: case 929: case 931: case 932: case 933: case 934: case 935: + case 936: case 937: case 938: case 939: case 1040: case 1041: case 1042: case 1043: case 1044: case 1045: case 1046: + case 1047: case 1048: case 1049: case 1050: case 1051: case 1052: case 1053: case 1054: case 1055: case 1056: case 1057: case 1058: + case 1059: case 1060: case 1061: case 1062: case 1063: case 1064: case 1065: case 1066: case 1067: case 1068: case 1069: case 1070: + case 1071: + lc = (utf32 + 32); + break; + case 256: case 257: case 258: case 259: case 260: case 261: case 262: case 263: case 264: case 265: + case 266: case 267: case 268: case 269: case 270: case 271: case 272: case 273: case 274: case 275: case 276: case 277: + case 278: case 279: case 280: case 281: case 282: case 283: case 284: case 285: case 286: case 287: case 288: case 289: + case 290: case 291: case 292: case 293: case 294: case 295: case 296: case 297: case 298: case 299: case 300: case 301: + case 302: case 303: case 305: case 306: case 307: case 308: case 309: case 310: case 330: case 331: + case 332: case 333: case 334: case 335: case 336: case 337: case 338: case 339: case 340: case 341: case 342: case 343: + case 344: case 345: case 346: case 347: case 348: case 349: case 350: case 351: case 352: case 353: case 354: case 355: + case 356: case 357: case 358: case 359: case 360: case 361: case 362: case 363: case 364: case 365: case 366: case 367: + case 368: case 369: case 370: case 371: case 372: case 373: case 374: case 416: case 417: case 418: case 419: + case 420: case 478: case 479: case 480: case 481: case 482: case 483: case 484: case 485: case 486: case 487: + case 488: case 489: case 490: case 491: case 492: case 493: case 494: case 504: case 505: case 506: case 507: + case 508: case 509: case 510: case 511: case 512: case 513: case 514: case 515: case 516: case 517: case 518: case 519: + case 520: case 521: case 522: case 523: case 524: case 525: case 526: case 527: case 528: case 529: case 530: case 531: + case 532: case 533: case 534: case 535: case 536: case 537: case 538: case 539: case 540: case 541: case 542: + case 546: case 547: case 548: case 549: case 550: case 551: case 552: case 553: case 554: case 555: case 556: case 557: + case 558: case 559: case 560: case 561: case 562: case 984: case 985: case 986: case 987: case 988: case 989: + case 990: case 991: case 992: case 993: case 994: case 995: case 996: case 997: case 998: case 999: case 1000: case 1001: + case 1002: case 1003: case 1004: case 1005: case 1006: case 1120: case 1121: case 1122: case 1123: case 1124: case 1125: + case 1126: case 1127: case 1128: case 1129: case 1130: case 1131: case 1132: case 1133: case 1134: case 1135: case 1136: case 1137: + case 1138: case 1139: case 1140: case 1141: case 1142: case 1143: case 1144: case 1145: case 1146: case 1147: case 1148: case 1149: + case 1150: case 1151: case 1152: case 1162: case 1163: case 1164: case 1165: case 1166: case 1167: case 1168: case 1169: + case 1170: case 1171: case 1172: case 1173: case 1174: case 1175: case 1176: case 1177: case 1178: case 1179: case 1180: case 1181: + case 1182: case 1183: case 1184: case 1185: case 1186: case 1187: case 1188: case 1189: case 1190: case 1191: case 1192: case 1193: + case 1194: case 1195: case 1196: case 1197: case 1198: case 1199: case 1200: case 1201: case 1202: case 1203: case 1204: case 1205: + case 1206: case 1207: case 1208: case 1209: case 1210: case 1211: case 1212: case 1213: case 1214: case 1232: case 1233: + case 1234: case 1235: case 1236: case 1237: case 1238: case 1239: case 1240: case 1241: case 1242: case 1243: case 1244: case 1245: + case 1246: case 1247: case 1248: case 1249: case 1250: case 1251: case 1252: case 1253: case 1254: case 1255: case 1256: case 1257: + case 1258: case 1259: case 1260: case 1261: case 1262: case 1263: case 1264: case 1265: case 1266: case 1267: case 1268: + case 1280: case 1281: case 1282: case 1283: case 1284: case 1285: case 1286: case 1287: case 1288: case 1289: case 1290: case 1291: + case 1292: case 1293: case 1294: + if ( !(((utf32) % 2 == 1))) { + lc = (utf32 + 1); + } + break; + case 313: case 314: case 315: case 316: case 317: case 318: case 319: case 320: case 321: case 322: + case 323: case 324: case 325: case 326: case 327: case 377: case 378: case 379: case 380: case 381: + case 459: case 460: case 461: case 462: case 463: case 464: case 465: case 466: case 467: case 468: case 469: case 470: + case 471: case 472: case 473: case 474: case 475: case 1217: case 1218: case 1219: case 1220: case 1221: case 1222: + case 1223: case 1224: case 1225: case 1226: case 1227: case 1228: case 1229: + if (((utf32) % 2 == 1)) { + lc = (utf32 + 1); + } + break; + case 1024: case 1025: case 1026: case 1027: case 1028: case 1029: case 1030: case 1031: case 1032: case 1033: + case 1034: case 1035: case 1036: case 1037: case 1038: case 1039: + lc = (utf32 + 80); + break; + case 1329: case 1330: case 1331: case 1332: case 1333: case 1334: case 1335: case 1336: case 1337: case 1338: + case 1339: case 1340: case 1341: case 1342: case 1343: case 1344: case 1345: case 1346: case 1347: case 1348: case 1349: case 1350: + case 1351: case 1352: case 1353: case 1354: case 1355: case 1356: case 1357: case 1358: case 1359: case 1360: case 1361: case 1362: + case 1363: case 1364: case 1365: case 1366: + lc = (utf32 + 48); + break; + case 304: + lc = 105; + break; + case 376: + lc = 255; + break; + case 385: + lc = 595; + break; + case 386: + lc = 387; + break; + case 388: + lc = 389; + break; + case 390: + lc = 596; + break; + case 391: + lc = 392; + break; + case 393: + lc = 598; + break; + case 394: + lc = 599; + break; + case 395: + lc = 396; + break; + case 398: + lc = 477; + break; + case 399: + lc = 601; + break; + case 400: + lc = 603; + break; + case 401: + lc = 402; + break; + case 403: + lc = 608; + break; + case 404: + lc = 611; + break; + case 406: + lc = 617; + break; + case 407: + lc = 616; + break; + case 408: + lc = 409; + break; + case 412: + lc = 623; + break; + case 413: + lc = 626; + break; + case 415: + lc = 629; + break; + case 422: + lc = 640; + break; + case 423: + lc = 424; + break; + case 425: + lc = 643; + break; + case 428: + lc = 429; + break; + case 430: + lc = 648; + break; + case 431: + lc = 432; + break; + case 433: + lc = 650; + break; + case 434: + lc = 651; + break; + case 435: + lc = 436; + break; + case 437: + lc = 438; + break; + case 439: + lc = 658; + break; + case 440: + lc = 441; + break; + case 444: + lc = 445; + break; + case 452: + lc = 454; + break; + case 453: + lc = 454; + break; + case 455: + lc = 457; + break; + case 456: + lc = 457; + break; + case 458: + lc = 460; + break; + case 497: + lc = 499; + break; + case 498: + lc = 499; + break; + case 500: + lc = 501; + break; + case 502: + lc = 405; + break; + case 503: + lc = 447; + break; + case 544: + lc = 414; + break; + case 902: + lc = 940; + break; + case 904: + lc = 941; + break; + case 905: + lc = 942; + break; + case 906: + lc = 943; + break; + case 908: + lc = 972; + break; + case 910: + lc = 973; + break; + case 911: + lc = 974; + break; + case 1012: + lc = 952; + break; + case 1015: + lc = 1016; + break; + case 1017: + lc = 1010; + break; + case 1018: + lc = 1019; + break; + case 1272: + lc = 1273; + break; + default: + break; + } + } + return lc; +} + +/** + * Converts utf32 input to uppercase + * @param utf32 : a single character encoded in UTF32 + * @return a single uppercase character encoded in UTF32 +*/ +static picoos_uint32 base_utf32_uppercase (picoos_uint32 utf32) +{ + picoos_uint32 lc; + + lc = utf32; + if (((utf32 >= 65345) && (utf32 <= 65370))) { + lc = (utf32 - 32); + } else if (((utf32 >= 66600) && (utf32 <= 66639))) { + lc = (utf32 - 40); + } else if (((utf32 >= 7681) && (utf32 <= 9449))) { + switch (utf32) { + case 7681: case 7682: case 7683: case 7684: case 7685: case 7686: case 7687: case 7688: case 7689: case 7690: + case 7691: case 7692: case 7693: case 7694: case 7695: case 7696: case 7697: case 7698: case 7699: case 7700: case 7701: case 7702: + case 7703: case 7704: case 7705: case 7706: case 7707: case 7708: case 7709: case 7710: case 7711: case 7712: case 7713: case 7714: + case 7715: case 7716: case 7717: case 7718: case 7719: case 7720: case 7721: case 7722: case 7723: case 7724: case 7725: case 7726: + case 7727: case 7728: case 7729: case 7730: case 7731: case 7732: case 7733: case 7734: case 7735: case 7736: case 7737: case 7738: + case 7739: case 7740: case 7741: case 7742: case 7743: case 7744: case 7745: case 7746: case 7747: case 7748: case 7749: case 7750: + case 7751: case 7752: case 7753: case 7754: case 7755: case 7756: case 7757: case 7758: case 7759: case 7760: case 7761: case 7762: + case 7763: case 7764: case 7765: case 7766: case 7767: case 7768: case 7769: case 7770: case 7771: case 7772: case 7773: case 7774: + case 7775: case 7776: case 7777: case 7778: case 7779: case 7780: case 7781: case 7782: case 7783: case 7784: case 7785: case 7786: + case 7787: case 7788: case 7789: case 7790: case 7791: case 7792: case 7793: case 7794: case 7795: case 7796: case 7797: case 7798: + case 7799: case 7800: case 7801: case 7802: case 7803: case 7804: case 7805: case 7806: case 7807: case 7808: case 7809: case 7810: + case 7811: case 7812: case 7813: case 7814: case 7815: case 7816: case 7817: case 7818: case 7819: case 7820: case 7821: case 7822: + case 7823: case 7824: case 7825: case 7826: case 7827: case 7828: case 7829: case 7841: case 7842: case 7843: case 7844: + case 7845: case 7846: case 7847: case 7848: case 7849: case 7850: case 7851: case 7852: case 7853: case 7854: case 7855: case 7856: + case 7857: case 7858: case 7859: case 7860: case 7861: case 7862: case 7863: case 7864: case 7865: case 7866: case 7867: case 7868: + case 7869: case 7870: case 7871: case 7872: case 7873: case 7874: case 7875: case 7876: case 7877: case 7878: case 7879: case 7880: + case 7881: case 7882: case 7883: case 7884: case 7885: case 7886: case 7887: case 7888: case 7889: case 7890: case 7891: case 7892: + case 7893: case 7894: case 7895: case 7896: case 7897: case 7898: case 7899: case 7900: case 7901: case 7902: case 7903: case 7904: + case 7905: case 7906: case 7907: case 7908: case 7909: case 7910: case 7911: case 7912: case 7913: case 7914: case 7915: case 7916: + case 7917: case 7918: case 7919: case 7920: case 7921: case 7922: case 7923: case 7924: case 7925: case 7926: case 7927: case 7928: + case 7929: + if (((utf32) % 2 == 1)) { + lc = (utf32 - 1); + } + break; + case 7936: case 7937: case 7938: case 7939: case 7940: case 7941: case 7942: case 7943: case 7952: + case 7953: case 7954: case 7955: case 7956: case 7957: case 7968: case 7969: case 7970: case 7971: case 7972: case 7973: + case 7974: case 7975: case 7984: case 7985: case 7986: case 7987: case 7988: case 7989: case 7990: case 7991: + case 8000: case 8001: case 8002: case 8003: case 8004: case 8005: case 8032: case 8033: case 8034: case 8035: case 8036: + case 8037: case 8038: case 8039: case 8064: case 8065: case 8066: case 8067: case 8068: case 8069: case 8070: case 8071: + case 8080: case 8081: case 8082: case 8083: case 8084: case 8085: case 8086: case 8087: case 8096: case 8097: + case 8098: case 8099: case 8100: case 8101: case 8102: case 8103: + lc = (utf32 + 8); + break; + case 8017: case 8018: case 8019: case 8020: case 8021: case 8022: case 8023: + if (((utf32) % 2 == 1)) { + lc = (utf32 + 8); + } + break; + case 8560: case 8561: case 8562: case 8563: case 8564: case 8565: case 8566: case 8567: case 8568: case 8569: + case 8570: case 8571: case 8572: case 8573: case 8574: case 8575: + lc = (utf32 - 16); + break; + case 9424: case 9425: case 9426: case 9427: case 9428: case 9429: case 9430: case 9431: case 9432: case 9433: + case 9434: case 9435: case 9436: case 9437: case 9438: case 9439: case 9440: case 9441: case 9442: case 9443: case 9444: case 9445: + case 9446: case 9447: case 9448: case 9449: + lc = (utf32 - 26); + break; + case 7835: + lc = 7776; + break; + case 8048: + lc = 8122; + break; + case 8049: + lc = 8123; + break; + case 8050: + lc = 8136; + break; + case 8051: + lc = 8137; + break; + case 8052: + lc = 8138; + break; + case 8053: + lc = 8139; + break; + case 8054: + lc = 8154; + break; + case 8055: + lc = 8155; + break; + case 8056: + lc = 8184; + break; + case 8057: + lc = 8185; + break; + case 8058: + lc = 8170; + break; + case 8059: + lc = 8171; + break; + case 8060: + lc = 8186; + break; + case 8061: + lc = 8187; + break; + case 8112: + lc = 8120; + break; + case 8113: + lc = 8121; + break; + case 8115: + lc = 8124; + break; + case 8126: + lc = 921; + break; + case 8131: + lc = 8140; + break; + case 8144: + lc = 8152; + break; + case 8145: + lc = 8153; + break; + case 8160: + lc = 8168; + break; + case 8161: + lc = 8169; + break; + case 8165: + lc = 8172; + break; + case 8179: + lc = 8188; + break; + default: + break; + } + } else { + switch (utf32) { + case 97: case 98: case 99: case 100: case 101: case 102: case 103: case 104: case 105: case 106: + case 107: case 108: case 109: case 110: case 111: case 112: case 113: case 114: case 115: case 116: case 117: case 118: + case 119: case 120: case 121: case 122: case 224: case 225: case 226: case 227: case 228: case 229: case 230: + case 231: case 232: case 233: case 234: case 235: case 236: case 237: case 238: case 239: case 240: case 241: case 242: + case 243: case 244: case 245: case 246: case 247: case 248: case 249: case 250: case 251: case 252: case 253: case 254: + case 945: case 946: case 947: case 948: case 949: case 950: case 951: case 952: case 953: case 954: case 955: + case 956: case 957: case 958: case 959: case 960: case 961: case 963: case 964: case 965: case 966: case 967: + case 968: case 969: case 970: case 971: case 1072: case 1073: case 1074: case 1075: case 1076: case 1077: case 1078: + case 1079: case 1080: case 1081: case 1082: case 1083: case 1084: case 1085: case 1086: case 1087: case 1088: case 1089: case 1090: + case 1091: case 1092: case 1093: case 1094: case 1095: case 1096: case 1097: case 1098: case 1099: case 1100: case 1101: case 1102: + case 1103: + if ((utf32 != 247)) { + lc = (utf32 - 32); + } + break; + case 257: case 258: case 259: case 260: case 261: case 262: case 263: case 264: case 265: case 266: + case 267: case 268: case 269: case 270: case 271: case 272: case 273: case 274: case 275: case 276: case 277: case 278: + case 279: case 280: case 281: case 282: case 283: case 284: case 285: case 286: case 287: case 288: case 289: case 290: + case 291: case 292: case 293: case 294: case 295: case 296: case 297: case 298: case 299: case 300: case 301: case 302: + case 303: case 304: case 306: case 307: case 308: case 309: case 310: case 311: case 331: case 332: + case 333: case 334: case 335: case 336: case 337: case 338: case 339: case 340: case 341: case 342: case 343: case 344: + case 345: case 346: case 347: case 348: case 349: case 350: case 351: case 352: case 353: case 354: case 355: case 356: + case 357: case 358: case 359: case 360: case 361: case 362: case 363: case 364: case 365: case 366: case 367: case 368: + case 369: case 370: case 371: case 372: case 373: case 374: case 375: case 417: case 418: case 419: case 420: + case 421: case 481: case 482: case 483: case 484: case 485: case 486: case 487: case 488: case 489: case 490: + case 491: case 492: case 493: case 494: case 495: case 507: case 508: case 509: case 510: case 511: + case 513: case 514: case 515: case 516: case 517: case 518: case 519: case 520: case 521: case 522: case 523: case 524: + case 525: case 526: case 527: case 528: case 529: case 530: case 531: case 532: case 533: case 534: case 535: case 536: + case 537: case 538: case 539: case 540: case 541: case 542: case 543: case 544: case 546: case 547: case 548: + case 549: case 550: case 551: case 552: case 553: case 554: case 555: case 556: case 557: case 558: case 559: case 560: + case 561: case 562: case 563: case 985: case 986: case 987: case 988: case 989: case 990: case 991: case 992: + case 993: case 994: case 995: case 996: case 997: case 998: case 999: case 1000: case 1001: case 1002: case 1003: case 1004: + case 1005: case 1006: case 1007: case 1121: case 1122: case 1123: case 1124: case 1125: case 1126: case 1127: case 1128: + case 1129: case 1130: case 1131: case 1132: case 1133: case 1134: case 1135: case 1136: case 1137: case 1138: case 1139: case 1140: + case 1141: case 1142: case 1143: case 1144: case 1145: case 1146: case 1147: case 1148: case 1149: case 1150: case 1151: case 1152: + case 1153: case 1163: case 1164: case 1165: case 1166: case 1167: case 1168: case 1169: case 1170: case 1171: case 1172: + case 1173: case 1174: case 1175: case 1176: case 1177: case 1178: case 1179: case 1180: case 1181: case 1182: case 1183: case 1184: + case 1185: case 1186: case 1187: case 1188: case 1189: case 1190: case 1191: case 1192: case 1193: case 1194: case 1195: case 1196: + case 1197: case 1198: case 1199: case 1200: case 1201: case 1202: case 1203: case 1204: case 1205: case 1206: case 1207: case 1208: + case 1209: case 1210: case 1211: case 1212: case 1213: case 1214: case 1215: case 1233: case 1234: case 1235: case 1236: + case 1237: case 1238: case 1239: case 1240: case 1241: case 1242: case 1243: case 1244: case 1245: case 1246: case 1247: case 1248: + case 1249: case 1250: case 1251: case 1252: case 1253: case 1254: case 1255: case 1256: case 1257: case 1258: case 1259: case 1260: + case 1261: case 1262: case 1263: case 1264: case 1265: case 1266: case 1267: case 1268: case 1269: case 1281: case 1282: + case 1283: case 1284: case 1285: case 1286: case 1287: case 1288: case 1289: case 1290: case 1291: case 1292: case 1293: case 1294: + case 1295: + if (((utf32) % 2 == 1)) { + lc = (utf32 - 1); + } + break; + case 314: case 315: case 316: case 317: case 318: case 319: case 320: case 321: case 322: case 323: + case 324: case 325: case 326: case 327: case 328: case 378: case 379: case 380: case 381: case 382: + case 464: case 465: case 466: case 467: case 468: case 469: case 470: case 471: case 472: case 473: case 474: case 475: + case 476: case 1218: case 1219: case 1220: case 1221: case 1222: case 1223: case 1224: case 1225: case 1226: case 1227: + case 1228: case 1229: case 1230: + if ( !(((utf32) % 2 == 1))) { + lc = (utf32 - 1); + } + break; + case 1104: case 1105: case 1106: case 1107: case 1108: case 1109: case 1110: case 1111: case 1112: case 1113: + case 1114: case 1115: case 1116: case 1117: case 1118: case 1119: + lc = (utf32 - 80); + break; + case 1377: case 1378: case 1379: case 1380: case 1381: case 1382: case 1383: case 1384: case 1385: case 1386: + case 1387: case 1388: case 1389: case 1390: case 1391: case 1392: case 1393: case 1394: case 1395: case 1396: case 1397: case 1398: + case 1399: case 1400: case 1401: case 1402: case 1403: case 1404: case 1405: case 1406: case 1407: case 1408: case 1409: case 1410: + case 1411: case 1412: case 1413: case 1414: + lc = (utf32 - 48); + break; + case 181: + lc = 924; + break; + case 255: + lc = 376; + break; + case 305: + lc = 73; + break; + case 383: + lc = 83; + break; + case 387: + lc = 386; + break; + case 389: + lc = 388; + break; + case 392: + lc = 391; + break; + case 396: + lc = 395; + break; + case 402: + lc = 401; + break; + case 405: + lc = 502; + break; + case 409: + lc = 408; + break; + case 414: + lc = 544; + break; + case 424: + lc = 423; + break; + case 429: + lc = 428; + break; + case 432: + lc = 431; + break; + case 436: + lc = 435; + break; + case 438: + lc = 437; + break; + case 441: + lc = 440; + break; + case 445: + lc = 444; + break; + case 447: + lc = 503; + break; + case 453: + lc = 452; + break; + case 454: + lc = 452; + break; + case 456: + lc = 455; + break; + case 457: + lc = 455; + break; + case 459: + lc = 458; + break; + case 460: + lc = 458; + break; + case 462: + lc = 461; + break; + case 477: + lc = 398; + break; + case 479: + lc = 478; + break; + case 498: + lc = 497; + break; + case 499: + lc = 497; + break; + case 501: + lc = 500; + break; + case 505: + lc = 504; + break; + case 595: + lc = 385; + break; + case 596: + lc = 390; + break; + case 598: + lc = 393; + break; + case 599: + lc = 394; + break; + case 601: + lc = 399; + break; + case 603: + lc = 400; + break; + case 608: + lc = 403; + break; + case 611: + lc = 404; + break; + case 616: + lc = 407; + break; + case 617: + lc = 406; + break; + case 623: + lc = 412; + break; + case 626: + lc = 413; + break; + case 629: + lc = 415; + break; + case 640: + lc = 422; + break; + case 643: + lc = 425; + break; + case 648: + lc = 430; + break; + case 650: + lc = 433; + break; + case 651: + lc = 434; + break; + case 658: + lc = 439; + break; + case 837: + lc = 921; + break; + case 940: + lc = 902; + break; + case 941: + lc = 904; + break; + case 942: + lc = 905; + break; + case 943: + lc = 906; + break; + case 962: + lc = 931; + break; + case 972: + lc = 908; + break; + case 973: + lc = 910; + break; + case 974: + lc = 911; + break; + case 976: + lc = 914; + break; + case 977: + lc = 920; + break; + case 981: + lc = 934; + break; + case 982: + lc = 928; + break; + case 1008: + lc = 922; + break; + case 1009: + lc = 929; + break; + case 1010: + lc = 1017; + break; + case 1013: + lc = 917; + break; + case 1016: + lc = 1015; + break; + case 1019: + lc = 1018; + break; + case 1273: + lc = 1272; + break; + default: + break; + } + } + return lc; +} + +/** + * Gets the UTF8 character 'utf8char' from the UTF8 string 'utf8str' from + * position 'pos' + * @param utf8str: utf8 string + * @param pos: position from where the utf8 character is copied + * (also output set as position of the next utf8 character in the utf8 string) + * @param utf8char: zero terminated utf8 character containing 1 to 4 bytes (output) +*/ +static void picobase_get_utf8char (picoos_uint8 utf8[], picoos_int32 * pos, picobase_utf8char utf8char) +{ + + int i; + int l; + + utf8char[0] = 0; + l = picobase_det_utf8_length(utf8[*pos]); + i = 0; + while ((((i < l) && (i < PICOBASE_UTF8_MAXLEN)) && (utf8[*pos] != 0))) { + utf8char[i] = utf8[*pos]; + (*pos)++; + i++; + } + utf8char[i] = 0; +} + + +picoos_uint8 picobase_get_next_utf8char(const picoos_uint8 *utf8s, + const picoos_uint32 utf8slenmax, + picoos_uint32 *pos, + picobase_utf8char utf8char) { + picoos_uint8 i; + picoos_uint8 len; + picoos_uint32 poscnt; + + utf8char[0] = 0; + len = picobase_det_utf8_length(utf8s[*pos]); + if ((((*pos) + len) > utf8slenmax) || + (len > PICOBASE_UTF8_MAXLEN)) { + return FALSE; + } + + poscnt = *pos; + i = 0; + while ((i < len) && (utf8s[poscnt] != 0)) { + utf8char[i] = utf8s[poscnt]; + poscnt++; + i++; + } + utf8char[i] = 0; + if ((i < len) && (utf8s[poscnt] == 0)) { + return FALSE; + } + *pos = poscnt; + return TRUE; +} + +picoos_uint8 picobase_get_next_utf8charpos(const picoos_uint8 *utf8s, + const picoos_uint32 utf8slenmax, + picoos_uint32 *pos) { + picoos_uint8 i; + picoos_uint8 len; + picoos_uint32 poscnt; + + len = picobase_det_utf8_length(utf8s[*pos]); + if ((((*pos) + len) > utf8slenmax) || + (len > PICOBASE_UTF8_MAXLEN)){ + return FALSE; + } + + poscnt = *pos; + i = 0; + while ((i < len) && (utf8s[poscnt] != 0)) { + poscnt++; + i++; + } + if ((i < len) && (utf8s[poscnt] == 0)) { + return FALSE; + } + *pos = poscnt; + return TRUE; +} + +picoos_uint8 picobase_get_prev_utf8char(const picoos_uint8 *utf8s, + const picoos_uint32 utf8slenmin, + picoos_uint32 *pos, + picobase_utf8char utf8char) { + picoos_uint8 i, j; + picoos_uint8 len; + picoos_uint32 poscnt; + + utf8char[0] = 0; + if ((*pos) == 0) { + return FALSE; + } + poscnt = (*pos) - 1; + i = 1; + while ((i <= PICOBASE_UTF8_MAXLEN) && (poscnt >= utf8slenmin) && + (utf8s[poscnt] != 0)) { + len = picobase_det_utf8_length(utf8s[poscnt]); + if (len == i) { + for (j = 0; j < len; j++) { + utf8char[j] = utf8s[poscnt + j]; + } + utf8char[j] = 0; + *pos = poscnt; + return TRUE; + } + i++; + poscnt--; + } + return FALSE; +} + +picoos_uint8 picobase_get_prev_utf8charpos(const picoos_uint8 *utf8s, + const picoos_uint32 utf8slenmin, + picoos_uint32 *pos) { + picoos_uint8 i; + picoos_uint8 len; + picoos_uint32 poscnt; + + if ((*pos) == 0) { + return FALSE; + } + poscnt = (*pos) - 1; + i = 1; + while ((i <= PICOBASE_UTF8_MAXLEN) && (poscnt >= utf8slenmin) && + (utf8s[poscnt] != 0)) { + len = picobase_det_utf8_length(utf8s[poscnt]); + if (len == i) { + *pos = poscnt; + return TRUE; + } + i++; + poscnt--; + } + return FALSE; +} + +/** + * Converts utf8 input to utf32 + * @param utf8[] : character encoded in utf8 + * @param done : boolean indicating the completion of the operation (FALSE: conversion not done) + * @return a single character encoded in UTF32 +*/ +static picobase_utf32 picobase_utf8_to_utf32 (picoos_uint8 utf8[], picoos_uint8 * done) +{ + (*done) = TRUE; + if ((utf8[0] < (picoos_uint8)'\200')) { + return utf8[0]; + } else if ((utf8[0] >= (picoos_uint8)'\370')) { + return 0; + } else if ((utf8[0] >= (picoos_uint8)'\360')) { + return ((((262144 * (utf8[0] % 8)) + (4096 * (utf8[1] % 64))) + (64 * (utf8[2] % 64))) + (utf8[3] % 64)); + } else if ((utf8[0] >= (picoos_uint8)'\340')) { + return (((4096 * (utf8[0] % 16)) + (64 * (utf8[1] % 64))) + (utf8[2] % 64)); + } else if ((utf8[(0)] >= (picoos_uint8)'\300')) { + return ((64 * (utf8[0] % 32)) + (utf8[1] % 64)); + } else { + (*done) = FALSE; + return 0; + } +} + +static picoos_int32 picobase_utf32_to_utf8 (picobase_utf32 utf32, picobase_utf8 utf8[], picoos_int32 utf8MaxLen, picoos_uint8 * done) +{ + picoos_int32 len; + + (*done) = TRUE; + if (utf8MaxLen >= 4) { + if (utf32 < 128) { + len = 1; + utf8[0] = utf32; + } else if (utf32 < 2048) { + len = 2; + utf8[1] = (128 + (utf32 % 64)); + utf32 = (utf32 / 64); + utf8[0] = (192 + (utf32 % 32)); + } else if (utf32 < 65536) { + len = 3; + utf8[2] = (128 + (utf32 % 64)); + utf32 = (utf32 / 64); + utf8[1] = (128 + (utf32 % 64)); + utf32 = (utf32 / 64); + utf8[0] = (224 + utf32); + } else if (utf32 < 1048576) { + len = 4; + utf8[3] = (128 + (utf32 % 64)); + utf32 = (utf32 / 64); + utf8[2] = (128 + (utf32 % 64)); + utf32 = (utf32 / 64); + utf8[1] = (128 + (utf32 % 64)); + utf32 = (utf32 / 64); + utf8[0] = (240 + utf32); + } else { + (*done) = FALSE; + return 0; + } + if (len <= (utf8MaxLen-1)) { + utf8[len] = 0; + } + return len; + } else { + (*done) = FALSE; + return 0; + } +} + + +extern picoos_int32 picobase_lowercase_utf8_str (picoos_uchar utf8str[], picoos_char lowercase[], int lowercaseMaxLen, picoos_uint8 * done) +{ + picobase_utf8char utf8char; + picoos_int32 i; + picoos_int32 j; + picoos_int32 k; + picoos_int32 l; + picobase_utf32 utf32; + picoos_uint8 done1; + + k = 0; + i = 0; + (*done) = TRUE; + while (utf8str[i] != 0) { + picobase_get_utf8char(utf8str,& i,utf8char); + utf32 = picobase_utf8_to_utf32(utf8char, & done1); + utf32 = base_utf32_lowercase(utf32); + l = picobase_utf32_to_utf8(utf32, utf8char, PICOBASE_UTF8_MAXLEN, & done1); + j = 0; + while ((j < l) && (k < (lowercaseMaxLen-1))) { + lowercase[k] = utf8char[j]; + k++; + j++; + } + *done = *done && (j == l); + } + lowercase[k] = 0; + return k; +} + + +extern picoos_int32 picobase_uppercase_utf8_str (picoos_uchar utf8str[], picoos_char uppercase[], int uppercaseMaxLen, picoos_uint8 * done) +{ + picobase_utf8char utf8char; + picoos_int32 i; + picoos_int32 j; + picoos_int32 k; + picoos_int32 l; + picobase_utf32 utf32; + picoos_uint8 done1; + + k = 0; + i = 0; + (*done) = TRUE; + while (utf8str[i] != 0) { + picobase_get_utf8char(utf8str,& i,utf8char); + utf32 = picobase_utf8_to_utf32(utf8char, & done1); + utf32 = base_utf32_uppercase(utf32); + l = picobase_utf32_to_utf8(utf32, utf8char, PICOBASE_UTF8_MAXLEN, & done1); + j = 0; + while ((j < l) && (k < (uppercaseMaxLen-1))) { + uppercase[k] = utf8char[j]; + k++; + j++; + } + *done = *done && (j == l); + } + uppercase[k] = 0; + return k; +} + + +extern picoos_bool picobase_is_utf8_uppercase (picoos_uchar utf8str[], picoos_int32 utf8strmaxlen) +{ + picobase_utf8char utf8char; + picoos_int32 i; + picoos_uint32 utf32; + picoos_bool done; + picoos_bool isUpperCase; + + isUpperCase = TRUE; + i = 0; + while (isUpperCase && (i <= utf8strmaxlen-1) && (utf8str[i] != 0)) { + picobase_get_utf8char(utf8str,& i,utf8char); + utf32 = picobase_utf8_to_utf32(utf8char,& done); + isUpperCase = isUpperCase && (utf32 == base_utf32_uppercase(utf32)); + } + return isUpperCase; +} + + +extern picoos_bool picobase_is_utf8_lowercase (picoos_uchar utf8str[], picoos_int32 utf8strmaxlen) +{ + picobase_utf8char utf8char; + picoos_int32 i; + picoos_uint32 utf32; + picoos_bool done; + picoos_bool isLowerCase; + + isLowerCase = TRUE; + i = 0; + while (isLowerCase && (i <= utf8strmaxlen-1) && (utf8str[i] != 0)) { + picobase_get_utf8char(utf8str,& i,utf8char); + utf32 = picobase_utf8_to_utf32(utf8char,& done); + isLowerCase = isLowerCase && (utf32 == base_utf32_lowercase(utf32)); + } + return isLowerCase; +} + + +#ifdef __cplusplus +} +#endif + + + +/* end */ diff --git a/pico/lib/picobase.h b/pico/lib/picobase.h new file mode 100644 index 0000000..1c384e1 --- /dev/null +++ b/pico/lib/picobase.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picobase.h + * + * base functionality + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#ifndef PICOBASE_H_ +#define PICOBASE_H_ + +#include "picoos.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +/* maximum number of bytes of an UTF8 character */ +#define PICOBASE_UTF8_MAXLEN 4 + +typedef picoos_uint8 picobase_utf8char[PICOBASE_UTF8_MAXLEN+1]; /* always zero terminated */ +typedef picoos_uint8 picobase_utf8; +typedef picoos_uint16 picobase_utf16; +typedef picoos_uint32 picobase_utf32; + +/* ***************************************************************/ +/* Unicode UTF8 functions */ +/* ***************************************************************/ + +/** + * Determines the number of UTF8 characters contained in + * the UTF8 string 'utf8str' of maximum length maxlen (in bytes) + * @param utf8str : a string encoded in UTF8 + * @param maxlen : max length (in bytes) accessible in utf8str + * @return >=0 : length of the UTF8 string in number of UTF8 characters + * up to the first '\0' or maxlen + * @return <0 : not starting with a valid UTF8 character + * @remarks strict implementation, not allowing invalid utf8 +*/ +picoos_int32 picobase_utf8_length(const picoos_uint8 *utf8str, + const picoos_uint16 maxlen); + + +/** + * Determines the number of bytes an UTF8 character used based + * on the first byte of the UTF8 character + * @param firstchar: the first (and maybe only) byte of an UTF8 character + * @return positive value in {1,4} : number of bytes of the UTF8 character + * @return 0 :if not a valid UTF8 character start + * @remarks strict implementation, not allowing invalid utf8 +*/ +/* picoos_uint8 picobase_det_utf8_length(const picoos_uint8 firstchar); */ + +#define picobase_det_utf8_length(x) ( ((x)<(picoos_uint8)'\200')?1:(((x)>=(picoos_uint8)'\370')?0:(((x)>=(picoos_uint8)'\360')?4:(((x)>=(picoos_uint8)'\340')?3:(((x)>=(picoos_uint8)'\300')?2:0)))) ) + +/** + * Converts the content of 'utf8str' to lowercase and stores it on 'lowercase' + * on the first byte of the UTF8 character + * @param utf8str : utf8 string + * @param lowercaseMaxLen : maximal number of bytes available in 'lowercase' + * @param lowercase : string converted to lowercase (output) + * @param done : flag to report success/failure of the operation (output) + * @return TRUE if successful, FALSE otherwise +*/ +picoos_int32 picobase_lowercase_utf8_str (picoos_uchar utf8str[], picoos_char lowercase[], picoos_int32 lowercaseMaxLen, picoos_uint8 * done); + +/** + * Converts the content of 'utf8str' to upperrcase and stores it on 'uppercase' + * @param utf8str : utf8 string + * @param uppercase : string converted to uppercase (output) + * @param uppercaseMaxLen : maximal number of bytes available in 'uppercase' + * @param done : flag to report success/failure of the operation (output) + * @return TRUE if successful, FALSE otherwise +*/ +picoos_int32 picobase_uppercase_utf8_str (picoos_uchar utf8str[], picoos_char uppercase[], int uppercaseMaxLen, picoos_uint8 * done); + +/** + * Gets next UTF8 character 'utf8char' from the UTF8 string + * 'utf8s' starting at position 'pos' + * @param utf8s : UTF8 string + * @param utf8slenmax : max length accessible in utf8s + * @param pos : position from where the UTF8 character is checked and copied + * (set also as output to the position directly following the UTF8 char) + * @param utf8char : zero terminated UTF8 character containing 1 to 4 bytes (output) + * @return TRUE if okay + * @return FALSE if there is no valid UTF8 char or no more UTF8 char available within utf8len +*/ +picoos_uint8 picobase_get_next_utf8char(const picoos_uint8 *utf8s, + const picoos_uint32 utf8slenmax, + picoos_uint32 *pos, + picobase_utf8char utf8char); + +/** + * Same as picobase_get_next_utf8char + * without copying the char to utf8char +*/ +picoos_uint8 picobase_get_next_utf8charpos(const picoos_uint8 *utf8s, + const picoos_uint32 utf8slenmax, + picoos_uint32 *pos); + +/** + * Gets previous UTF8 character 'utf8char' from the UTF8 string + * 'utf8s' starting the backward search at position 'pos-1' + * @param utf8s : UTF8 string + * @param utf8slenmin : min length accessible in utf8s + * @param pos : the search for the prev UTF8 char starts at [pos-1] + * (set also as output to the start position of the prev UTF8 character) + * @param utf8char : zero terminated UTF8 character containing 1 to 4 bytes (output) + * @return TRUE if okay + * @return FALSE if there is no valid UTF8 char preceeding pos or no more UTF8 char available within utf8len +*/ +picoos_uint8 picobase_get_prev_utf8char(const picoos_uint8 *utf8s, + const picoos_uint32 utf8slenmin, + picoos_uint32 *pos, + picobase_utf8char utf8char); + +/** + * Same as picobase_get_prev_utf8char + * without copying the char to utf8char +*/ +picoos_uint8 picobase_get_prev_utf8charpos(const picoos_uint8 *utf8s, + const picoos_uint32 utf8slenmin, + picoos_uint32 *pos); + + +/** + * returns TRUE if the input string is UTF8 and uppercase + * @param str : UTF8 string + * @param strmaxlen : max length for the input string + * @return TRUE if string is UTF8 and uppercase + * @return FALSE otherwise +*/ +extern picoos_bool picobase_is_utf8_uppercase (picoos_uchar str[], picoos_int32 strmaxlen); + +/** + * returns TRUE if the input string is UTF8 and lowercase + * @param str : UTF8 string + * @param strmaxlen : max length for the input string + * @return TRUE if string is UTF8 and lowercase + * @return FALSE otherwise +*/ +extern picoos_bool picobase_is_utf8_lowercase (picoos_uchar str[], picoos_int32 strmaxlen); + +#ifdef __cplusplus +} +#endif + +#endif /*PICOBASE_H_*/ diff --git a/pico/lib/picocep.c b/pico/lib/picocep.c new file mode 100644 index 0000000..e544322 --- /dev/null +++ b/pico/lib/picocep.c @@ -0,0 +1,2028 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picocep.c + * + * Phonetic to Acoustic Mapping PU - Implementation + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +/** + * @addtogroup picocep + * Pico Cepstral Smoothing \n + * + itemtype, iteminfo1, iteminfo2, content -> TYPE(INFO1,INFO2)content + in the following + + items input + + processed: + + - PHONE(PHONID,StatesPerPhone)[FramesPerState|f0Index|mgcIndex]{StatesPerPhone} + + (StatesPerPhone is a constant (5) for the time being. The content size is therfore allways 34) + + unprocessed: + - all other item types are forwarded through the PU without modification + + items output + + FRAME(PHONID,F0 [?])ceps{25} + + each PHONE produces at least StatesPerPhone FRAME (if each state has FramesPerState == 1), but usually more. + + minimal input size (before processing starts) + + other limitations + + */ +#include "picodefs.h" +#include "picoos.h" +#include "picodbg.h" +#include "picodata.h" +#include "picokpdf.h" +#include "picodsp.h" +#include "picocep.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +#define PICOCEP_MAXWINLEN 10000 /* maximum number of frames that can be smoothed, i.e. maximum sentence length */ +#define PICOCEP_MSGSTR_SIZE 32 +#define PICOCEP_IN_BUFF_SIZE PICODATA_BUFSIZE_DEFAULT + +#define PICOCEP_OUT_DATA_FORMAT PICODATA_ITEMINFO1_FRAME_PAR_DATA_FORMAT_FIXED /* we output coefficients as fixed point values */ + +#define PICOCEP_STEPSTATE_COLLECT 0 +#define PICOCEP_STEPSTATE_PROCESS_PARSE 1 +#define PICOCEP_STEPSTATE_PROCESS_SMOOTH 2 +#define PICOCEP_STEPSTATE_PROCESS_FRAME 3 +#define PICOCEP_STEPSTATE_FEED 4 + +#define PICOCEP_LFZINVPOW 31 /* cannot be higher than 31 because 1< 2^16 */ + picoos_uint8 * outVoiced; + picoos_uint16 outVoicedReadPos, outVoicedWritePos; + + /*---------------------- LINGWARE related data -------------------*/ + /* pdflfz knowledge base */ + picokpdf_PdfMUL pdflfz, pdfmgc; + +} cep_subobj_t; + +/** + * picocep_highestBit + * @brief find the highest non-zero bit in input x + * @remarks this may be implemented by comparing x to powers of 2 + * or instead of calling this function perform multiplication + * and consult overflow register if available on target + * @note implemented as a series of macros + */ + +#define picocep_highestBitNZ(x) (x>=POW17?(x>=POW25?(x>=POW29?(x>=POW31?31:(x>=POW30?30:29)):(x>=POW27?(x>=POW28?28:27):(x>=POW26?26:25))):(x>=POW21?(x>=POW23?(x>=POW24?24:23):(x>=POW22?22:21)):(x>=POW19?(x>=POW20?20:19):(x>=POW18?18:17)))):(x>=POW9?(x>=POW13?(x>=POW15?(x>=POW16?16:15):(x>=POW14?14:13)):(x>=POW11?(x>=POW12?12:11):(x>=POW10?10:9))):(x>=POW5?(x>=POW7?(x>=POW8?8:7):(x>=POW6?6:5)):(x>=POW3?(x>=POW4?4:3):(x>=POW2?2:1))))) +#define picocep_highestBitU(x) (x==0?0:picocep_highestBitNZ(x)) +#define picocep_highestBitS(x,zz) (x==0?0:(x<0?((zz)=(-x),picocep_highestBitNZ(zz)):picocep_highestBitNZ(x))) + +/* ------------------------------------------------------------------------------ + Internal function definitions + ---------------------------------------------------------------------------------*/ + +static void initSmoothing(cep_subobj_t * cep); + +static picoos_int32 getFromPdf(picokpdf_PdfMUL pdf, picoos_uint32 vecstart, + picoos_uint8 cepnum, picocep_WantMeanOrIvar_t wantMeanOrIvar, + picocep_WantStaticOrDelta_t wantStaticOrDeltax); + +static void invMatrix(cep_subobj_t * cep, picoos_uint16 N, + picoos_int16 *smoothcep, picoos_uint8 cepnum, + picokpdf_PdfMUL pdf, picoos_uint8 invpow, picoos_uint8 invDoubleDec); + +static picoos_uint8 makeWUWandWUm(cep_subobj_t * cep, picokpdf_PdfMUL pdf, + picoos_uint16 *indices, picoos_uint16 b, picoos_uint16 N, + picoos_uint8 cepnum); + +static void getDirect(picokpdf_PdfMUL pdf, picoos_uint16 *indices, + picoos_uint16 activeEndPos, + picoos_uint8 cepnum, picoos_int16 *smoothcep); + +static void getVoiced(picokpdf_PdfMUL pdf, picoos_uint16 *indices, + picoos_uint16 activeEndPos, + picoos_uint8 *smoothcep); + +static picoos_uint16 get_pi_uint16(picoos_uint8 * buf, picoos_uint16 *pos); + +static void treat_phone(cep_subobj_t * cep, picodata_itemhead_t * ihead); + +static picoos_uint8 forwardingItem(picodata_itemhead_t * ihead); + +static picodata_step_result_t cepStep(register picodata_ProcessingUnit this, + picoos_int16 mode, picoos_uint16 * numBytesOutput); + +/* -------------------------------------------- + * generic PU management + * -------------------------------------------- + */ + +/** + * initialization of a cep PU (processing unit) + * @param this : handle to a cep PU struct + * @return PICO_OK : init succeded + * @return PICO_ERR_OTHER : init failed + * @callgraph + * @callergraph + */ +static pico_status_t cepInitialize(register picodata_ProcessingUnit this, picoos_int32 resetMode) +{ + /*pico_status_t nRes;*/ + cep_subobj_t * cep; + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + cep = (cep_subobj_t *) this->subObj; + /* inBuf */ + cep->inBufSize = PICODATA_BUFSIZE_CEP; + cep->inReadPos = 0; + cep->inWritePos = 0; + /* headx and cbuf */ + cep->headxBottom = cep->headxWritePos = 0; + cep->cbufBufSize = PICOCEP_MAXSIZE_CBUF; + cep->cbufWritePos = 0; + /* outBuf */ + cep->outBufSize = PICODATA_MAX_ITEMSIZE; + cep->outReadPos = 0; + cep->outWritePos = 0; + /* indices* */ + cep->indexReadPos = 0; + cep->indexWritePos = 0; + /* outCep, outF0, outVoiced */ + cep->outXCepReadPos = 0; + cep->outXCepWritePos = 0; + cep->outVoicedReadPos = 0; + cep->outVoicedWritePos = 0; + cep->outF0ReadPos = 0; + cep->outF0WritePos = 0; + + cep->needMoreInput = 0; + cep->inIgnoreState = 0; + cep->sentenceEnd = FALSE; + cep->procState = PICOCEP_STEPSTATE_COLLECT; + + cep->nNumFrames = 0; + + /*----------------------------------------------------------------- + * MANAGE Item I/O control management + ------------------------------------------------------------------*/ + cep->activeEndPos = PICOCEP_MAXWINLEN; + + if (resetMode == PICO_RESET_FULL) { + /* kb pdflfz */ + cep->pdflfz = picokpdf_getPdfMUL( + this->voice->kbArray[PICOKNOW_KBID_PDF_LFZ]); + + /* kb pdfmgc */ + cep->pdfmgc = picokpdf_getPdfMUL( + this->voice->kbArray[PICOKNOW_KBID_PDF_MGC]); + + /* kb tab phones */ + /* cep->phones = + picoktab_getPhones(this->voice->kbArray[PICOKNOW_KBID_TAB_PHONES]); */ + + /*---------------------- other working variables ---------------------------*/ + /* define the (constant) FRAME_PAR item header */ + cep->framehead.type = PICODATA_ITEM_FRAME_PAR; + cep->framehead.info1 = PICOCEP_OUT_DATA_FORMAT; + cep->framehead.info2 = cep->pdfmgc->ceporder; + cep->framehead.len = sizeof(picoos_uint16) + (cep->framehead.info2 + 4) + * sizeof(picoos_uint16); + cep->scmeanpowLFZ = cep->pdflfz->bigpow - cep->pdflfz->meanpow; + cep->scmeanpowMGC = cep->pdfmgc->bigpow - cep->pdfmgc->meanpow; + + cep->scmeanLFZ = (1 << (picoos_uint32) cep->scmeanpowLFZ); + + cep->scmeanMGC = (1 << (picoos_uint32) cep->scmeanpowMGC); + + } + /* constants used in makeWUWandWUm */ + initSmoothing(cep); + + + return PICO_OK; +}/*cepInitialize*/ + +/** + * termination of a cep PU (processing unit) + * @param this : handle to a cep PU struct + * @return PICO_OK : termination succeded + * @return PICO_ERR_OTHER : termination failed + * @callgraph + * @callergraph + */ +static pico_status_t cepTerminate(register picodata_ProcessingUnit this) +{ + return PICO_OK; +} + +/** + * deallocation of a cep PU internal sub object + * @param this : handle to a cep PU struct + * @param mm : handle of the engine memory manager + * @return PICO_OK : deallocation succeded + * @return PICO_ERR_OTHER : deallocation failed + * @callgraph + * @callergraph + */ +static pico_status_t cepSubObjDeallocate(register picodata_ProcessingUnit this, + picoos_MemoryManager mm) +{ + + mm = mm; /* avoid warning "var not used in this function"*/ +#if defined(PICO_DEVEL_MODE) + printf("number of long mult is %d, number of short mult is %i\n",numlongmult,numshortmult); +#else + PICODBG_INFO_MSG(("number of long mult is %d, number of short mult is %i\n",numlongmult,numshortmult)); +#endif + if (NULL != this) { + cep_subobj_t * cep = (cep_subobj_t *) this->subObj; + picoos_deallocate(this->common->mm, (void *) &cep->outXCep); + picoos_deallocate(this->common->mm, (void *) &cep->outVoiced); + picoos_deallocate(this->common->mm, (void *) &cep->outF0); + picoos_deallocate(this->common->mm, (void *) &this->subObj); + } + return PICO_OK; +} + +/** + * creates a new cep PU (processing unit) + * @param mm : engine memory manager object pointer + * @param common : engine common object pointer + * @param cbIn : PU input buffer + * @param cbOut : PU output buffer + * @param voice : the voice descriptor object + * @return a valid PU handle if creation succeded + * @return NULL : creation failed + * @callgraph + * @callergraph + */ +picodata_ProcessingUnit picocep_newCepUnit(picoos_MemoryManager mm, + picoos_Common common, picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, picorsrc_Voice voice) +{ + picodata_ProcessingUnit this = picodata_newProcessingUnit(mm, common, cbIn, + cbOut, voice); + cep_subobj_t * cep; + + if (this == NULL) { + return NULL; + } + this->initialize = cepInitialize; + + PICODBG_DEBUG(("set this->step to cepStep")); + + this->step = cepStep; + this->terminate = cepTerminate; + this->subDeallocate = cepSubObjDeallocate; + this->subObj = picoos_allocate(mm, sizeof(cep_subobj_t)); + + cep = (cep_subobj_t *) this->subObj; + + if (this->subObj == NULL) { + picoos_deallocate(mm, (void*) &this); + return NULL; + }; + + /* allocate output coeeficient buffers */ + cep->outF0 = (picoos_int16 *) picoos_allocate(this->common->mm, + PICOCEP_MAXWINLEN * PICOKPDF_MAX_MUL_LFZ_CEPORDER + * sizeof(picoos_int16)); + cep->outXCep = (picoos_int16 *) picoos_allocate(this->common->mm, + PICOCEP_MAXWINLEN * PICOKPDF_MAX_MUL_MGC_CEPORDER + * sizeof(picoos_int16)); + cep->outVoiced = (picoos_uint8 *) picoos_allocate(this->common->mm, + PICOCEP_MAXWINLEN * sizeof(picoos_uint8)); + + if ((NULL == cep->outF0) || (NULL == cep->outXCep) || (NULL + == cep->outVoiced)) { + picoos_deallocate(this->common->mm, (void *) &(cep->outF0)); + picoos_deallocate(this->common->mm, (void *) &(cep->outXCep)); + picoos_deallocate(this->common->mm, (void *) &(cep->outVoiced)); + picoos_deallocate(mm, (void*) &cep); + picoos_deallocate(mm, (void*) &this); + return NULL; + } + cepInitialize(this, PICO_RESET_FULL); + + return this; +}/*picocep_newCepUnit*/ + +/* -------------------------------------------- + * processing and internal functions + * -------------------------------------------- + */ + +/** + * multiply by 1<= 0) + b = a << pow; + else + b = -(-a << pow); + } else { + /* clip to maximum positive or negative value */ + b = 1U << 31; /* maximum negative value */ + if (a > 0) { + b -= 1; /* maximum positive value */ + }PICODBG_WARN(("picocep_fixptmultpow warning: overflow in fixed point multiplication %i*1<<%i. Clipping to %i\n", a, pow, b)); + } + return b; +} + +/** + * divide by 1< 0) { + a = (a + big) >> pow; + } else { + a = -1 * ((-1 * a + big) >> pow); + } + + return a; +} + +/** + * fixed point multiplication of x and y for large values of x or y or both + * @param x,y : operands 1 & 2, in fixed point S:M:N representation + * @param bigpow (int) : normalization factor=2**N, where N=number of binary decimal digits + * @param invDoubleDec : boolean indicating that x has double decimal size. + * do extra division by 1<= 0) { + a = x >> bigpow; + if (a >= 0) + b = x - (a << bigpow); + else + b = x + (-a << bigpow); + } else { + a = -1 * ((x * -1) >> bigpow); /* most significant 2 bytes of x */ + if (a >= 0) + b = x - (a << bigpow); + else + b = x + (-a << bigpow); + } + + /* least significant 2 bytes of x i.e. x modulo big */ + /* c = floor(y/big); */ + if (y >= 0) { + c = y >> bigpow; + if (c >= 0) + d = y - (c << bigpow); + else + d = y + (-c << bigpow); + } else { + c = -1 * ((y * -1) >> bigpow); + if (c >= 0) + d = y - (c << bigpow); + else + d = y + (-c << bigpow); + } + + if (invDoubleDec == 1) { + e = a * d + b * c + picocep_fixptdivpow(b * d, bigpow); + z = a * c + picocep_fixptdivpow(e, bigpow); + } else { + picoos_int32 f = a * c; + if (f >= 0) + f <<= bigpow; + else + f = -(-f << bigpow); + z = f + (a * d + b * c) + picocep_fixptdivpow(b * d, + bigpow); /* 4 mult and 3 add instead of 1 mult. */ + } + + return z; +} + +/** + * fixed point multiplication of x and y + * @param x,y : operands 1 & 2, in fixed point S:M:N representation + * @param bigpow (int) : normalization factor=2**N, where N=number of binary decimal digits + * @param invDoubleDec : boolean indicating that x has double decimal size. + * do extra division by 1< 31 + pow) { + PICODBG_WARN(("picocep_fixptmult warning: overflow in fixed point multiplication %i*%i, multsz = %i, pow = %i, decrease bigpow\n", x, y, multsz, pow)); + } +#endif + z = picocep_fixptmultdouble(x, y, bigpow, invDoubleDec); /* perform long multiplication for large x and y */ +#if defined(PICO_DEBUG) + numlongmult++; /* keep track of number of long multiplications */ +#endif + } + return z; +}/* picocep_fixptmult */ + +/** + * fixed point ^division of a vs b + * @param a,b : operands 1 & 2, in fixed point S:M:N representation + * @param bigpow (int) : normalization factor=2**N, where N=number of binary decimal digits + * @return z(int) : result, in fixed point S:M:N representation + * Notes + * - input and output values are 32 bit signed integers + * meant to represent a S.M.N encoding of a floating point value where + * - S : 1 sign bit + * - M : number of binary integer digits (M=32-1-N) + * - N : number of binary decimal digits (N=log2(big)) + * - standard implementation of division by iteratively calculating + * the remainder and setting corresponding bit + * calculate integer part by integer division (DIV), + * then add X bits of precision in decimal part + * @callgraph + * @callergraph + */ +static picoos_int32 picocep_fixptdiv(picoos_int32 a, picoos_int32 b, + picoos_uint8 bigpow) +{ + picoos_int32 r, c, f, h, stop; + r = (a < 0) ? -a : a; /* take absolute value; b is already guaranteed to be positive in smoothing operation */ + if (r == 0) { + return 0; + } + c = 0; + stop = 0; + + /* can speed up slightly by setting stop = 2 => slightly less precision */ + h = r / b; /* in first loop h can be multiple bits, after first loop h can only be 0 or 1 */ + /* faster implementation on target by using comparison instead of DIV? */ + /* For our LDL even in first loop h <= 1, but not in backward step */ + c = c + (h << bigpow); /* after first loop simply set bit */ + r = r - h * b; /* corresponds to modulo operation */ + bigpow--; + r <<= 1; + + while ((bigpow > stop) && (r != 0)) { /* calculate bigpow bits after fixed point */ + /* can speed up slightly by setting stop = 2 => slightly less precision */ + if (r >= b) { + c += (1 << bigpow); /* after first loop simply set bit */ + r -= b; /* corresponds to modulo operation */ + } + bigpow--; + r <<= 1; + } + + if (r != 0) { + f = r + (b >> 1); + if (f >= b) { + if (f >= b + b) { + c += 2; + } else { + c++; + } + } + } + /* final step: do rounding (experimentally improves accuracy for our problem) */ + c = (a >= 0) ? c : -c; /* b is guaranteed to be positive because corresponds to diag0 */ + return c; +}/* picocep_fixptdiv */ + +/** + * perform inversion of diagonal element of WUW matrix + * @param d : diagonal element to be inverted + * @param rowscpow (int) : fixed point base for each dimension of the vectors stored in the database + * @param bigpow (int) : fixed point base used during cepstral smoothing + * @param invpow : fixed point base of inverted pivot elements + * @return inverted pivot element + * @note + * - d is guaranteed positive + * @callgraph + * @callergraph + */ +static picoos_int32 picocep_fixptInvDiagEle(picoos_uint32 d, + picoos_uint8* rowscpow, picoos_uint8 bigpow, picoos_uint8 invpow) +{ + picoos_uint32 r, b, c, h, f, stop; + picoos_uint8 dlen; + /* picoos_int32 zz; */ + c = 0; + stop = 0; + + dlen = picocep_highestBitU(d); + if (invpow + bigpow > 30 + dlen) { /* c must be < 2^32, hence d which is >= 2^(dlen-1) must be > 2^(invpow+bigpow-32), or invpow+bigpow must be <= dlen+30*/ + *rowscpow = invpow + bigpow - 30 - dlen;PICODBG_DEBUG(("input to picocep_fixptInvDiagEle is %i <= 1<<%i = 1< 0) { + c += (h << bigpow); + r -= h * b; + } + bigpow--; + r <<= 1; + + /* loop */ + while ((bigpow > stop) && (r != 0)) { + if (r >= b) { + c += (1 << bigpow); + r -= b; + } + bigpow--; + r <<= 1; + } + + if (r != 0) { + f = r + (b >> 1); + if (f >= b) { + if (f >= b + b) { + c += 2; + } else { + c++; + } + } + } + + return c; +}/* picocep_fixptInvDiagEle */ + +/** + * perform division of two operands a and b by multiplication by inverse of b + * @param a (int32) : operand 1 in fixed point S:M:N representation + * @param invb(uint32) : inverse of operand b, in fixed point P:Q representation (sign is positive) + * @param bigpow(uint8) : N = bigpow when invDoubleDec==0, else N = 2*bigpow + * @param invpow(uint8) : Q = invpow = number of binary decimal digits for invb + * @param invDoubleDec : boolean to indicate that a and the return value c have 2*N binary decimal digits instead of N + * @return c(int32) : result in fixed point S:v:w where w = 2*N when invDoubleDec == 1 + * @note Calls + * - picocep_fixptmult + * @callgraph + * @callergraph + */ +static picoos_int32 picocep_fixptinv(picoos_int32 a, picoos_uint32 invb, + picoos_uint8 bigpow, picoos_uint8 invpow, picoos_uint8 invDoubleDec) +{ + picoos_int32 c; + picoos_int8 normpow; + + c = picocep_fixptmult(a, invb, bigpow, invDoubleDec); + + /* if invDoubleDec==0, picocep_fixptmult assumes a and invb are in base 1< normfactor = big^3/big2 + */ + if (invDoubleDec == 1) { + normpow = 3 * bigpow; + } else { + normpow = bigpow; + } + if (normpow < invpow) { + /* divide with rounding */ + c = picocep_fixptdivpow(c, invpow - normpow); + } else { + c = picocep_fixptmultpow(c, normpow - invpow); + } + return c; +} + +/** + * initializes the coefficients to calculate delta and delta-delta values and the squares of the coefficients + * @param cep : the CEP PU sub-object handle + * @callgraph + * @callergraph + */ +static void initSmoothing(cep_subobj_t * cep) +{ + cep->xi[0] = 1; + cep->xi[1] = -1; + cep->xi[2] = 2; + cep->xi[3] = -4; + cep->xi[4] = 2; + cep->xsqi[0] = 1; + cep->xsqi[1] = 1; + cep->xsqi[2] = 4; + cep->xsqi[3] = 16; + cep->xsqi[4] = 4; + + cep->x1[0] = -1; + cep->x1[1] = 2; + cep->xsq1[0] = 1; + cep->xsq1[1] = 4; + + cep->x2[0] = -1; + cep->x2[1] = -4; + cep->x2[2] = 2; + cep->xsq2[0] = 1; + cep->xsq2[1] = 16; + cep->xsq2[2] = 4; + + cep->xm[0] = 1; + cep->xm[1] = 2; + cep->xm[2] = -4; + cep->xsqm[0] = 1; + cep->xsqm[1] = 4; + cep->xsqm[2] = 16; + + cep->xn[0] = 1; + cep->xn[1] = 2; + cep->xsqn[0] = 1; + cep->xsqn[1] = 4; +} + +/** + * matrix inversion + * @param cep : PU sub object pointer + * @param N + * @param smoothcep : pointer to picoos_int16, sequence of smoothed cepstral vectors + * @param cepnum : cepstral dimension to be treated + * @param pdf : pdf resource + * @param invpow : fixed point base for inverse + * @param invDoubleDec : boolean indicating that result of picocep_fixptinv has fixed point base 2*bigpow + * picocep_fixptmult absorbs double decimal size by dividing its result by extra factor big + * @return void + * @remarks diag0, diag1, diag2, WUm, invdiag0 globals needed in this function (object members in pico) + * @callgraph + * @callergraph + */ +static void invMatrix(cep_subobj_t * cep, picoos_uint16 N, + picoos_int16 *smoothcep, picoos_uint8 cepnum, + picokpdf_PdfMUL pdf, picoos_uint8 invpow, picoos_uint8 invDoubleDec) +{ + picoos_int32 j, v1, v2, h; + picoos_uint32 k; + picoos_uint8 rowscpow, prevrowscpow; + picoos_uint8 ceporder = pdf->ceporder; + picoos_uint8 bigpow = pdf->bigpow; + picoos_uint8 meanpow = pdf->meanpow; + + /* LDL factorization */ + prevrowscpow = 0; + cep->invdiag0[0] = picocep_fixptInvDiagEle(cep->diag0[0], &rowscpow, + bigpow, invpow); /* inverse has fixed point basis 1<diag1[0] >= 0) + cep->diag1[0] <<= rowscpow; + else + cep->diag1[0] = -(-cep->diag1[0] << rowscpow); + cep->diag1[0] = picocep_fixptinv(cep->diag1[0], + cep->invdiag0[0], bigpow, invpow, invDoubleDec); /* perform division via inverse */ + if (cep->diag2[0] >= 0) + cep->diag2[0] <<= rowscpow; + else + cep->diag2[0] = -(-cep->diag2[0] << rowscpow); + cep->diag2[0] = picocep_fixptinv(cep->diag2[0], + cep->invdiag0[0], bigpow, invpow, invDoubleDec); + if (cep->WUm[0] >= 0) + cep->WUm[0] = (cep->WUm[0]) << rowscpow; /* if diag0 too low, multiply LHS and RHS of row in matrix equation by 1<WUm[0] = -(-cep->WUm[0] << rowscpow); /* if diag0 too low, multiply LHS and RHS of row in matrix equation by 1<WUm[j] = cep->WUm[j] - picocep_fixptmult(cep->diag1[j - 1], + cep->WUm[j - 1], bigpow, invDoubleDec); + if (j > 1) { + cep->WUm[j] = cep->WUm[j] - picocep_fixptmult(cep->diag2[j - 2], + cep->WUm[j - 2], bigpow, invDoubleDec); + } + + /* update row j */ + v1 = picocep_fixptmult((cep->diag1[j - 1]) / (1 << rowscpow), + cep->diag0[j - 1], bigpow, invDoubleDec); /* undo scaling by 1<diag0[j] = cep->diag0[j] - picocep_fixptmult(cep->diag1[j - 1], + v1, bigpow, invDoubleDec); + if (j > 1) { + v2 = picocep_fixptmult((cep->diag2[j - 2]) / (1 << prevrowscpow), + cep->diag0[j - 2], bigpow, invDoubleDec); /* undo scaling by 1<diag0[j] = cep->diag0[j] - picocep_fixptmult( + cep->diag2[j - 2], v2, bigpow, invDoubleDec); + } + prevrowscpow = rowscpow; + cep->invdiag0[j] = picocep_fixptInvDiagEle(cep->diag0[j], &rowscpow, + bigpow, invpow); /* inverse has fixed point basis 1<WUm[j] >= 0) + cep->WUm[j] = (cep->WUm[j]) << rowscpow; + else + cep->WUm[j] = -(-cep->WUm[j] << rowscpow); + if (j < N - 1) { + h = picocep_fixptmult(cep->diag2[j - 1], v1, bigpow, invDoubleDec); + if (cep->diag1[j] - h >= 0) + cep->diag1[j] = picocep_fixptinv((cep->diag1[j] - h) << rowscpow, + cep->invdiag0[j], bigpow, invpow, invDoubleDec); /* eliminate column j below pivot */ + else + cep->diag1[j] = picocep_fixptinv(-(-(cep->diag1[j] - h) << rowscpow), + cep->invdiag0[j], bigpow, invpow, invDoubleDec); /* eliminate column j below pivot */ + } + if (j < N - 2) { + if (cep->diag2[j] >= 0) + cep->diag2[j] = picocep_fixptinv((cep->diag2[j]) << rowscpow, + cep->invdiag0[j], bigpow, invpow, invDoubleDec); /* eliminate column j below pivot */ + else + cep->diag2[j] = picocep_fixptinv(-(-cep->diag2[j] << rowscpow), + cep->invdiag0[j], bigpow, invpow, invDoubleDec); /* eliminate column j below pivot */ + } + } + + /* divide all entries of WUm by diag0 */ + for (j = 0; j < N; j++) { + cep->WUm[j] = picocep_fixptinv(cep->WUm[j], cep->invdiag0[j], bigpow, + invpow, invDoubleDec); + if (invDoubleDec == 1) { + cep->WUm[j] = picocep_fixptdivpow(cep->WUm[j], bigpow); + } + } + + /* backward substitution */ + for (j = N - 2; j >= 0; j--) { + cep->WUm[j] = cep->WUm[j] - picocep_fixptmult(cep->diag1[j], cep->WUm[j + + 1], bigpow, invDoubleDec); + if (j < N - 2) { + cep->WUm[j] = cep->WUm[j] - picocep_fixptmult(cep->diag2[j], + cep->WUm[j + 2], bigpow, invDoubleDec); + } + } + /* copy N frames into smoothcep (only for coeff # "cepnum") */ + /* coefficients normalized to occupy short; for correct waveform energy, divide by (1<<(bigpow-meanpow)) then convert e.g. to picoos_single */ + k = cepnum; + for (j = 0; j < N; j++) { + smoothcep[k] = (picoos_int16)(cep->WUm[j]/(1< At x W x A + * @remarks WUm --> At x W x b + * @callgraph + * @callergraph + */ +static picoos_uint8 makeWUWandWUm(cep_subobj_t * cep, picokpdf_PdfMUL pdf, + picoos_uint16 *indices, picoos_uint16 b, picoos_uint16 N, + picoos_uint8 cepnum) +{ + picoos_uint16 Id[2], Idd[3]; + /*picoos_uint32 vecstart, k;*/ + picoos_uint32 vecstart; + picoos_int32 *x = NULL, *xsq = NULL; + picoos_int32 mean, ivar; + picoos_uint16 i, j, numd = 0, numdd = 0; + picoos_uint8 vecsize = pdf->vecsize; + picoos_int32 prev_WUm, prev_diag0, prev_diag1, prev_diag1_1, prev_diag2; + + prev_WUm = prev_diag0 = prev_diag1 = prev_diag1_1 = prev_diag2 = 0; + for (i = 0; i < N; i++) { + + if ((1 < i) && (i < N - 2)) { + x = cep->xi; + xsq = cep->xsqi; + numd = 2; + numdd = 3; + Id[0] = Idd[0] = i - 1; + Id[1] = Idd[2] = i + 1; + Idd[1] = i; + } else if (i == 0) { + x = cep->x1; + xsq = cep->xsq1; + numd = numdd = 1; + Id[0] = Idd[0] = 1; + } else if (i == 1) { + x = cep->x2; + xsq = cep->xsq2; + numd = 1; + numdd = 2; + Id[0] = Idd[1] = 2; + Idd[0] = 1; + } else if (i == N - 2) { + x = cep->xm; + xsq = cep->xsqm; + numd = 1; + numdd = 2; + Id[0] = Idd[0] = N - 3; + Idd[1] = N - 2; + } else if (i == N - 1) { + x = cep->xn; + xsq = cep->xsqn; + numd = numdd = 1; + Id[0] = Idd[0] = N - 2; + } + + /* process static means and static inverse variances */ + if (i > 0 && indices[b + i] == indices[b + i - 1]) { + cep->diag0[i] = prev_diag0; + cep->WUm[i] = prev_WUm; + } else { + vecstart = indices[b + i] * vecsize; + ivar = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTIVAR, + PICOCEP_WANTSTATIC); + prev_diag0 = cep->diag0[i] = ivar << 2; /* multiply ivar by 4 (4 used to be first entry of xsq) */ + mean = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTMEAN, + PICOCEP_WANTSTATIC); + if (mean >= 0) + prev_WUm = cep->WUm[i] = mean << 1; /* multiply mean by 2 (2 used to be first entry of x) */ + else + prev_WUm = cep->WUm[i] = -(-mean << 1); /* multiply mean by 2 (2 used to be first entry of x) */ + } + + /* process delta means and delta inverse variances */ + for (j = 0; j < numd; j++) { + vecstart = indices[b + Id[j]] * vecsize; + ivar = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTIVAR, + PICOCEP_WANTDELTA); + cep->diag0[i] += xsq[j] * ivar; + + mean = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTMEAN, + PICOCEP_WANTDELTA); + if (mean != 0) { + cep->WUm[i] += x[j] * mean; + } + } + + /* process delta delta means and delta delta inverse variances */ + for (j = 0; j < numdd; j++) { + vecstart = indices[b + Idd[j]] * vecsize; + ivar = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTIVAR, + PICOCEP_WANTDELTA2); + cep->diag0[i] += xsq[numd + j] * ivar; + + mean = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTMEAN, + PICOCEP_WANTDELTA2); + if (mean != 0) { + cep->WUm[i] += x[numd + j] * mean; + } + } + + cep->diag0[i] = (cep->diag0[i] + 2) / 4; /* long DIV with rounding */ + cep->WUm[i] = (cep->WUm[i] + 1) / 2; /* long DIV with rounding */ + + /* calculate diag(A,-1) */ + if (i < N - 1) { + if (i < N - 2) { + if (i > 0 && indices[b + i + 1] == indices[b + i]) { + cep->diag1[i] = prev_diag1; + } else { + vecstart = indices[b + i + 1] * vecsize; + /* + diag1[i] = getFromPdf(pdf, vecstart, numvuv, ceporder, numdeltas, cepnum, + bigpow, meanpowUm, ivarpow, PICOCEP_WANTIVAR, PICOCEP_WANTDELTA2); + */ + prev_diag1 = cep->diag1[i] = getFromPdf(pdf, vecstart, + cepnum, PICOCEP_WANTIVAR, PICOCEP_WANTDELTA2); + } + /* + k = vecstart +pdf->numvuv+pdf->ceporder*2 + pdf->numdeltas*3 + + pdf->ceporder*2 +cepnum; + cep->diag1[i] = (picoos_int32)(pdf->content[k]) << pdf->bigpow; + */ + } else { + cep->diag1[i] = 0; + } + if (i > 0) { + if (i > 1 && indices[b + i] == indices[b + i - 1]) { + cep->diag1[i] += prev_diag1_1; + } else { + vecstart = indices[b + i] * vecsize; + /* + k = vecstart + pdf->numvuv + pdf->ceporder * 2 + pdf->numdeltas * 3 + pdf->ceporder * 2 + cepnum; + cep->diag1[i] += (picoos_int32)(pdf->content[k]) << pdf->bigpow; */ + /* cepnum'th delta delta ivar */ + + prev_diag1_1 = getFromPdf(pdf, vecstart, cepnum, + PICOCEP_WANTIVAR, PICOCEP_WANTDELTA2); + cep->diag1[i] += prev_diag1_1; + } + + } /*i < N-1 */ + cep->diag1[i] *= -2; + } + } + + /* calculate diag(A,-2) */ + for (i = 0; i < N - 2; i++) { + if (i > 0 && indices[b + i + 1] == indices[b + i]) { + cep->diag2[i] = prev_diag2; + } else { + vecstart = indices[b + i + 1] * vecsize; + /* + k = vecstart + pdf->numvuv + pdf->ceporder * 2 + pdf->numdeltas * 3 + pdf->ceporder * 2 + cepnum; + cep->diag2[i] = (picoos_int32)(pdf->content[k]) << pdf->bigpow; + k -= pdf->ceporder; + ivar = (picoos_int32)(pdf->content[k]) << pdf->bigpow; + */ + cep->diag2[i] = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTIVAR, + PICOCEP_WANTDELTA2); + ivar = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTIVAR, + PICOCEP_WANTDELTA); + cep->diag2[i] -= (ivar + 2) / 4; + prev_diag2 = cep->diag2[i]; + } + } + + return 0; +}/* makeWUWandWUm */ + +/** + * Retrieve actual values for MGC from PDF resource + * @param pdf : pointer to picoos_uint8, sequence of pdf vectors, each vector of length 1+ceporder*2+numdeltas*3+ceporder*3 + * @param vecstart : indices of pdf vectors for all frames in current sentence + * @param cepnum : cepstral dimension to be treated + * @param wantMeanOrIvar : flag to select mean or variance values + * @param wantStaticOrDeltax : flag to select static or delta values + * @return the actual value retrieved + * @callgraph + * @callergraph + */ +static picoos_int32 getFromPdf(picokpdf_PdfMUL pdf, picoos_uint32 vecstart, + picoos_uint8 cepnum, picocep_WantMeanOrIvar_t wantMeanOrIvar, + picocep_WantStaticOrDelta_t wantStaticOrDeltax) +{ + picoos_uint8 s, ind; + picoos_uint8 *p; + picoos_uint8 ceporder, ceporder2, cc; + picoos_uint32 k; + picoos_int32 mean = 0, ivar = 0; + + if (pdf->numdeltas == 0xFF) { + switch (wantMeanOrIvar) { + case PICOCEP_WANTMEAN: + switch (wantStaticOrDeltax) { + case PICOCEP_WANTSTATIC: + p = pdf->content + + (vecstart + pdf->numvuv + cepnum * 2); /* cepnum'th static mean */ + mean = ((picoos_int32) ((picoos_int16) (*(p + 1) << 8)) + | *p) << (pdf->meanpowUm[cepnum]); + break; + case PICOCEP_WANTDELTA: + cc = pdf->ceporder + cepnum; + p = pdf->content + (vecstart + pdf->numvuv + cc * 2); /* cepnum'th delta mean */ + mean = ((picoos_int32) ((picoos_int16) (*(p + 1) << 8)) + | *p); + if (mean >= 0) + mean <<= (pdf->meanpowUm[cc]); + else + mean = -(-mean << pdf->meanpowUm[cc]); + break; + case PICOCEP_WANTDELTA2: + cc = pdf->ceporder * 2 + cepnum; + p = pdf->content + (vecstart + pdf->numvuv + cc * 2); /* cepnum'th delta delta mean */ + mean = ((picoos_int32) ((picoos_int16) (*(p + 1) << 8)) + | *p); + if (mean >= 0) + mean <<= (pdf->meanpowUm[cc]); + else + mean = -(-mean << pdf->meanpowUm[cc]); + break; + default: + /* should never come here */ + PICODBG_ERROR(("unknown type wantStaticOrDeltax = %i", wantStaticOrDeltax)); + } + return mean; + break; + case PICOCEP_WANTIVAR: + switch (wantStaticOrDeltax) { + case PICOCEP_WANTSTATIC: + k = vecstart + pdf->numvuv + pdf->ceporder * 6 + cepnum; /* cepnum'th static ivar */ + ivar = (picoos_int32) (pdf->content[k]) + << (pdf->ivarpow[cepnum]); + break; + case PICOCEP_WANTDELTA: + ceporder = pdf->ceporder; + k = vecstart + pdf->numvuv + ceporder * 7 + cepnum; /* cepnum'th delta ivar */ + ivar = (picoos_int32) (pdf->content[k]) + << (pdf->ivarpow[ceporder + cepnum]); + break; + case PICOCEP_WANTDELTA2: + ceporder = pdf->ceporder; + k = vecstart + pdf->numvuv + ceporder * 8 + cepnum; /* cepnum'th delta delta ivar */ + ivar = (picoos_int32) (pdf->content[k]) + << (pdf->ivarpow[2 * ceporder + cepnum]); + break; + default: + /* should never get here */ + PICODBG_ERROR(("unknown type wantStaticOrDeltax = %i", wantStaticOrDeltax)); + } + return ivar; + break; + default: + /* should never come here */ + PICODBG_ERROR(("unknown type wantMeanOrIvar = %n", wantMeanOrIvar)); + return 0; + } + } else { + switch (wantMeanOrIvar) { + case PICOCEP_WANTMEAN: + switch (wantStaticOrDeltax) { + case PICOCEP_WANTSTATIC: + p = pdf->content + + (vecstart + pdf->numvuv + cepnum * 2); /* cepnum'th static mean */ + mean = ((picoos_int32) ((picoos_int16) (*(p + 1) << 8)) + | *p); + if (mean >= 0) + mean <<= (pdf->meanpowUm[cepnum]); + else + mean = -(-mean << (pdf->meanpowUm[cepnum])); + return mean; + break; + case PICOCEP_WANTDELTA: + ceporder = pdf->ceporder; + s = 0; + ind = 0; + while ((s < pdf->numdeltas) && (ind < cepnum || (ind + == 0 && cepnum == 0))) { /* rawmean deltas are sparse so investigate indices in column */ + k = vecstart + pdf->numvuv + ceporder * 2 + s; /* s'th delta index */ + ind = (picoos_uint8) (pdf->content[k]); /* is already picoos_uint8 but just to make explicit */ + if (ind == cepnum) { + k = vecstart + pdf->numvuv + ceporder * 2 + + pdf->numdeltas + s * 2; /* s'th sparse delta mean, corresponds to cepnum'th delta mean */ + mean + = ((picoos_int32) ((picoos_int16) ((pdf->content[k + + 1]) << 8)) | pdf->content[k]); + if (mean >= 0) + mean <<= (pdf->meanpowUm[ceporder + cepnum]); + else + mean = -(-mean << (pdf->meanpowUm[ceporder + cepnum])); + return mean; + } + s++; + } + return 0; + break; + case PICOCEP_WANTDELTA2: + ceporder = pdf->ceporder; + ceporder2 = ceporder * 2; + s = pdf->numdeltas; + ind = 2 * ceporder; + while ((s-- > 0) && (ind > ceporder + cepnum)) { /* rawmean deltas are sparse so investigate indices in column */ + k = vecstart + pdf->numvuv + ceporder2 + s; /* s'th delta index */ + ind = (picoos_uint8) (pdf->content[k]); /* is already picoos_uint8 but just to make explicit */ + if (ind == ceporder + cepnum) { + k = vecstart + pdf->numvuv + ceporder2 + + pdf->numdeltas + s * 2; /* s'th sparse delta mean, corresponds to cepnum'th delta delta mean */ + mean + = ((picoos_int32) ((picoos_int16) ((pdf->content[k + + 1]) << 8)) | pdf->content[k]); + if (mean >= 0) + mean <<= (pdf->meanpowUm[ceporder2 + cepnum]); + else + mean = -(-mean << (pdf->meanpowUm[ceporder2 + cepnum])); + return mean; + } + } + return 0; + break; + default: + PICODBG_ERROR(("getFromPdf: unknown type wantStaticOrDeltax = %i\n", wantStaticOrDeltax)); + return 0; + } + break; + case PICOCEP_WANTIVAR: + switch (wantStaticOrDeltax) { + case PICOCEP_WANTSTATIC: + k = vecstart + pdf->numvuv + pdf->ceporder * 2 + + pdf->numdeltas * 3 + cepnum; /* cepnum'th static ivar */ + ivar = (picoos_int32) (pdf->content[k]) + << (pdf->ivarpow[cepnum]); + break; + case PICOCEP_WANTDELTA: + ceporder = pdf->ceporder; + k = vecstart + pdf->numvuv + ceporder * 3 + + pdf->numdeltas * 3 + cepnum; /* cepnum'th delta ivar */ + ivar = (picoos_int32) (pdf->content[k]) + << (pdf->ivarpow[ceporder + cepnum]); + break; + case PICOCEP_WANTDELTA2: + ceporder2 = 2 * pdf->ceporder; + k = vecstart + pdf->numvuv + ceporder2 + pdf->numdeltas + * 3 + ceporder2 + cepnum; /* cepnum'th delta delta ivar */ + ivar = (picoos_int32) (pdf->content[k]) + << (pdf->ivarpow[ceporder2 + cepnum]); + break; + default: + PICODBG_ERROR(("unknown type wantStaticOrDeltax = %i", wantStaticOrDeltax)); + } + return ivar; + break; + default: + PICODBG_ERROR(("unknown type wantMeanOrIvar = %i", wantMeanOrIvar)); + return 0; + } + } + return 0; +} + +/** + * Retrieve actual values for MGC from PDF resource - Variant "Direct" + * @param pdf : pointer to picoos_uint8, sequence of pdf vectors, each vector of length 1+ceporder*2+numdeltas*3+ceporder*3 + * @param indices : indices of pdf vectors for all frames in current sentence + * @param activeEndPos : ?? + * @param cepnum : cepstral dimension to be treated + * @param smoothcep : ?? + * @return the actual value retrieved + * @callgraph + * @callergraph + */ +static void getDirect(picokpdf_PdfMUL pdf, picoos_uint16 *indices, + picoos_uint16 activeEndPos, + picoos_uint8 cepnum, picoos_int16 *smoothcep) +{ + picoos_uint16 i; + picoos_uint32 j; + picoos_uint32 vecstart; + picoos_int32 mean, ivar; + picoos_int32 prev_mean; + picoos_uint8 vecsize = pdf->vecsize; + picoos_uint8 order = pdf->ceporder; + + j = cepnum; + prev_mean = 0; + for (i = 0; i < activeEndPos; i++) { + if (i > 0 && indices[i] == indices[i - 1]) { + mean = prev_mean; + } else { + vecstart = indices[i] * vecsize; + mean = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTMEAN, + PICOCEP_WANTSTATIC); + ivar = getFromPdf(pdf, vecstart, cepnum, PICOCEP_WANTIVAR, + PICOCEP_WANTSTATIC); + prev_mean = mean = picocep_fixptdiv(mean, ivar, pdf->bigpow); + } + smoothcep[j] = (picoos_int16)(mean/(1<meanpow)); + j += order; + } +} + +/** + * Retrieve actual values for voicing from PDF resource + * @param pdf : pointer to picoos_uint8, sequence of pdf vectors, each vector of length 1+ceporder*2+numdeltas*3+ceporder*3 + * @param indices : indices of pdf vectors for all frames in current sentence + * @param activeEndPos : end position of indices to be considered + * @return smoothcep : the values retrieved + * @callgraph + * @callergraph + */ +static void getVoiced(picokpdf_PdfMUL pdf, picoos_uint16 *indices, + picoos_uint16 activeEndPos, + picoos_uint8 *smoothcep) +{ + picoos_uint16 i, j; + picoos_uint32 vecstart; + picoos_uint8 vecsize = pdf->vecsize; + + if (pdf->numvuv == 0) { + /* do nothing */ + } else { + for (i = 0, j = 0; i < activeEndPos; i++, j++) { + vecstart = indices[i] * vecsize; + smoothcep[j] = pdf->content[vecstart]; /* odd value is voiced, even if unvoiced */ + } + } +} + +/** reads platform-independent uint16 from buffer at *pos and advances *pos + * @param buf : buffer picoos_uint8 + * @param *pos : start position inside buffer of pi uint16 + * @return the uint16 + * @callgraph + * @callergraph + */ +static picoos_uint16 get_pi_uint16(picoos_uint8 * buf, picoos_uint16 *pos) +{ + picoos_uint16 res; + res = buf[(*pos)] | ((picoos_uint16) buf[(*pos) + 1] << 8); + *pos += 2; + return res; +} +/** + * Looks up indices of one phone item and fills index buffers. Consumes Item + * @param cep : the CEP PU sub object pointer + * @param ihead : pointer to the start of the phone item + * @callgraph + * @callergraph + */ +static void treat_phone(cep_subobj_t * cep, picodata_itemhead_t * ihead) +{ + picoos_uint16 state, frame, frames; + picoos_uint16 indlfz, indmgc; + picoos_uint16 pos; + picoos_uint8 bufferFull; + + /* treat all states + * for each state, repeat putting the index into the index buffer framesperstate times. + */ + /* set state and frame to the first state and frame in the phone to be considered */ + state = 0; /* the first state to be considered */ + frame = 0; /* the first frame to be considered */ + /* numFramesPerState: 2 byte, lf0Index: 2 byte, mgcIndex: 2 byte -> 6 bytes per state */ + PICODBG_DEBUG(("skipping to phone state %i ",state)); + pos = cep->inReadPos + PICODATA_ITEM_HEADSIZE + state * 6; + /* */ + PICODBG_DEBUG(("state info starts at inBuf pos %i ",pos)); + /* get the current frames per state */ + frames = get_pi_uint16(cep->inBuf, &pos); + /* */ + PICODBG_DEBUG(("number of frames for this phone state: %i",frames)); + /* */ + PICODBG_DEBUG(("PARSE starting with frame %i",frame)); + + bufferFull = cep->indexWritePos >= PICOCEP_MAXWINLEN; + while ((state < ihead->info2) && (bufferFull == FALSE)) { + + /* get the current state's lf0 and mgc indices and adjust according to state */ + /* the indices have to be calculated as follows: + * new index = (index-1) + stateoffset(state) */ + + indlfz = get_pi_uint16(cep->inBuf, &pos); /* lfz index */ + indlfz += -1 + cep->pdflfz->stateoffset[state]; /* transform index */ + indmgc = get_pi_uint16(cep->inBuf, &pos); /* mgc index */ + indmgc += -1 + cep->pdfmgc->stateoffset[state]; /* transform index */ + + /* are we reaching the end of the index buffers? */ + if ((cep->indexWritePos - frame) + frames > PICOCEP_MAXWINLEN) { + /* number of frames that will still fit */ + frames = PICOCEP_MAXWINLEN - (cep->indexWritePos - frame); + bufferFull = TRUE; + PICODBG_DEBUG(("smoothing buffer full at state=%i frame=%i",state, frame)); + } + while (frame < frames) { + cep->indicesMGC[cep->indexWritePos] = indmgc; + cep->indicesLFZ[cep->indexWritePos] = indlfz; + cep->phoneId[cep->indexWritePos] = ihead->info1; + cep->indexWritePos++; + frame++; + } + /* proceed to next state */ + PICODBG_DEBUG(("finished state %i with %i frames, now at index write pos %i", + state, frames,cep->indexWritePos)); + state++; + if (state < ihead->info2) { + frame = 0; + frames = get_pi_uint16(cep->inBuf, &pos); + } + } + /* consume the phone item */ + cep->inReadPos = cep->nextInPos; + /* */ + PICODBG_DEBUG(("finished phone, advancing inReadPos to %i",cep->inReadPos)); +} + +/** + * Returns true if an Item has to be forwarded to next PU + * @param ihead : pointer to item head structure + * @return TRUE : the item should be forwarded + * @return FALSE : the item should be consumed + * @callgraph + * @callergraph + */ +static picoos_uint8 forwardingItem(picodata_itemhead_t * ihead) +{ + if ((PICODATA_ITEM_CMD == ihead->type) && (PICODATA_ITEMINFO1_CMD_IGNSIG + == ihead->info1)) { + return FALSE; + } else { + return TRUE; + } +} + +/** + * performs a step of the cep processing + * @param this : pointer to current PU (Control Unit) + * @param mode : mode for the PU (not used) + * @param numBytesOutput : pointer to output number fo bytes produced + * @return one of the "picodata_step_result_t" values + * @callgraph + * @callergraph + */ +static picodata_step_result_t cepStep(register picodata_ProcessingUnit this, + picoos_int16 mode, picoos_uint16 * numBytesOutput) +{ + register cep_subobj_t * cep; + picodata_itemhead_t ihead /* , ohead */; + picoos_uint8 * icontents; + pico_status_t sResult = PICO_OK; + picoos_uint16 blen, clen; + picoos_uint16 numinb, numoutb; + +#if defined (PICO_DEBUG) + picoos_char msgstr[PICOCEP_MSGSTR_SIZE]; +#endif + numinb = 0; + numoutb = 0; + + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + cep = (cep_subobj_t *) this->subObj; + mode = mode; /* avoid warning "var not used in this function"*/ + + /*Init number of output bytes*/ + *numBytesOutput = 0; + + while (1) { /* exit via return */ + + PICODBG_DEBUG(("doing pu state %i", cep->procState)); + + switch (cep->procState) { + + case PICOCEP_STEPSTATE_COLLECT: + /* *************** item collector ***********************************/ + + PICODBG_TRACE(("COLLECT")); + + /*collecting items from the PU input buffer*/ + sResult = picodata_cbGetItem(this->cbIn, + &(cep->inBuf[cep->inWritePos]), cep->inBufSize + - cep->inWritePos, &blen); + if (PICO_EOF == sResult) { /* there are no more items available and we always need more data here */ + PICODBG_DEBUG(("COLLECT need more data, returning IDLE")); + return PICODATA_PU_IDLE; + } + + PICODBG_DEBUG(("got item, status: %d", sResult)); + + if ((PICO_OK == sResult) && (blen > 0)) { + /* we now have one item */ + cep->inWritePos += blen; + cep->procState = PICOCEP_STEPSTATE_PROCESS_PARSE; + } else { + /* ignore item and stay in collect */ + PICODBG_ERROR(("COLLECT got bad result %i", sResult)); + cep->inReadPos = cep->inWritePos = 0; + } + /* return PICODATA_PU_ATOMIC; */ + break; + + case PICOCEP_STEPSTATE_PROCESS_PARSE: + /* **************** put item indices into index buffers (with repetition) ******************/ + + PICODBG_TRACE(("PARSE")); + + PICODBG_DEBUG(("getting info from inBuf in range: [%i,%i[", cep->inReadPos, cep->inWritePos)); + if (cep->inWritePos <= cep->inReadPos) { + /* no more items in inBuf */ + /* we try to get more data */ + PICODBG_DEBUG(("no more items in inBuf, try to collect more")); + /* cep->needMoreInput = TRUE; */ + cep->inReadPos = cep->inWritePos = 0; + cep->procState = PICOCEP_STEPSTATE_COLLECT; + break; + } + /* look at the current item */ + /*verify that current item is valid */ + if (!picodata_is_valid_item(cep->inBuf + cep->inReadPos, + cep->inWritePos - cep->inReadPos)) { + PICODBG_ERROR(("found invalid item")); + sResult = picodata_get_iteminfo( + cep->inBuf + cep->inReadPos, cep->inWritePos + - cep->inReadPos, &ihead, &icontents);PICODBG_DEBUG(("PARSE bad item %s",picodata_head_to_string(&ihead,msgstr,PICOCEP_MSGSTR_SIZE))); + + return PICODATA_PU_ERROR; + } + + sResult = picodata_get_iteminfo(cep->inBuf + cep->inReadPos, + cep->inWritePos - cep->inReadPos, &ihead, &icontents); + + if (PICO_EXC_BUF_UNDERFLOW == sResult) { + /* no more items in inBuf */ + /* we try to get more data */ + PICODBG_DEBUG(("no more items in inBuf, try to collect more")); + /* cep->needMoreInput = TRUE; */ + cep->inReadPos = cep->inWritePos = 0; + cep->procState = PICOCEP_STEPSTATE_COLLECT; + break; + } else if (PICO_OK != sResult) { + PICODBG_ERROR(("unknown exception (sResult == %i)",sResult)); + return (picodata_step_result_t) picoos_emRaiseException( + this->common->em, sResult, NULL, NULL); + break; + } + + PICODBG_DEBUG(("PARSE looking at item %s",picodata_head_to_string(&ihead,msgstr,PICOCEP_MSGSTR_SIZE))); + + cep->nextInPos = PICODATA_ITEM_HEADSIZE + ihead.len; + + /* we decide what to do next depending on the item and the state of the index buffer: + * - process buffer if buffer not empty and sentence end or flush or ignsig/start (don't consume item yet) + * - fill buffer with (part of) phone contents if item is a phone + * - consume or copy for later output otherwise + */ + + if (cep->inIgnoreState) { + if ((PICODATA_ITEM_CMD == ihead.type) + && (PICODATA_ITEMINFO1_CMD_IGNSIG == ihead.info1) + && (PICODATA_ITEMINFO2_CMD_END == ihead.info2)) { + cep->inIgnoreState = 0; + }PICODBG_DEBUG(("cep: PARSE consuming item of inBuf")); + cep->inReadPos = cep->nextInPos; + break; + } + + /* see if it is a sentence end boundary or termination boundary (flush) and there are indices to smooth -> smooth */ + if ((PICODATA_ITEM_BOUND == ihead.type) + && ((PICODATA_ITEMINFO1_BOUND_SEND == ihead.info1) + || (PICODATA_ITEMINFO1_BOUND_TERM == ihead.info1)) + && (cep->indexWritePos > 0)) { + /* we smooth the buffer */ + cep->activeEndPos = cep->indexWritePos; + cep->sentenceEnd = TRUE; + /* output whatever we got */ + PICODBG_DEBUG(("cep: PARSE found sentence terminator; setting activeEndPos to %i",cep->activeEndPos)); + cep->procState = PICOCEP_STEPSTATE_PROCESS_SMOOTH; + break; + } else if (PICODATA_ITEM_PHONE == ihead.type) { + /* it is a phone */ + PICODBG_DEBUG(("cep: PARSE treating PHONE")); + treat_phone(cep, &ihead); + + } else { + if ((PICODATA_ITEM_CMD == ihead.type) + && (PICODATA_ITEMINFO1_CMD_IGNSIG == ihead.info1) + && (PICODATA_ITEMINFO2_CMD_START == ihead.info2)) { + cep->inIgnoreState = 1; + } + /* sentence end or flush remaining after frame or other non-processable item, e.g. command */ + /* do we have to forward? */ + if (forwardingItem(&ihead)) { + /* if no active frames, output immediately */ + if (cep->indexWritePos <= 0) { + /* copy item to outBuf */ + PICODBG_DEBUG(("PARSE copy item in inBuf to outBuf")); + picodata_copy_item(cep->inBuf + cep->inReadPos, + cep->inWritePos - cep->inReadPos, + cep->outBuf, cep->outBufSize, &blen); + cep->outWritePos += blen; + PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG], + (picoos_uint8 *)"cep: do forward item ", + cep->outBuf, PICODATA_MAX_ITEMSIZE); + /* output item and then go to parse to treat a new item. */ + cep->feedFollowState + = PICOCEP_STEPSTATE_PROCESS_PARSE; + cep->procState = PICOCEP_STEPSTATE_FEED; + } else if ((cep->headxWritePos < PICOCEP_MAXNR_HEADX) + && (cep->cbufWritePos + ihead.len + < cep->cbufBufSize)) { + /* there is enough space to store item */ + PICODBG_DEBUG(("unhandled item (type %c, length %i). Storing associated with index %i",ihead.type, ihead.len, cep->indexWritePos)); + sResult + = picodata_get_itemparts( + cep->inBuf + cep->inReadPos, + cep->inWritePos - cep->inReadPos, + &(cep->headx[cep->headxWritePos].head), + &(cep->cbuf[cep->cbufWritePos]), + cep->cbufBufSize + - cep->cbufWritePos, &clen); + + if (sResult != PICO_OK) { + PICODBG_ERROR(("problem getting item parts")); + picoos_emRaiseException(this->common->em, + sResult, NULL, NULL); + return PICODATA_PU_ERROR; + } + /* remember sync position */ + cep->headx[cep->headxWritePos].frame + = cep->indexWritePos; + + if (clen > 0) { + cep->headx[cep->headxWritePos].cind + = cep->cbufWritePos; + cep->cbufWritePos += clen; + } else { + cep->headx[cep->headxWritePos].cind = 0; + } + cep->headxWritePos++; + } else { + /* buffer full, smooth and output whatever we got */ + PICODBG_DEBUG(("PARSE is forced to smooth prematurely; setting activeEndPos to %i", cep->activeEndPos)); + cep->procState = PICOCEP_STEPSTATE_PROCESS_SMOOTH; + /* don't consume item yet */ + break; + } + } else { + }PICODBG_DEBUG(("cep: PARSE consuming item of inBuf")); + cep->inReadPos = cep->nextInPos; + } + break; + + case PICOCEP_STEPSTATE_PROCESS_SMOOTH: + /* **************** smooth (indexed) coefficients and store smoothed in outBuffers ****************/ + + PICODBG_TRACE(("SMOOTH")); + { + picokpdf_PdfMUL pdf; + + /* picoos_uint16 framesTreated = 0; */ + picoos_uint8 cepnum; + picoos_uint16 N; + + N = cep->activeEndPos; /* numframes in current step */ + + /* the range to be smoothed starts at 0 and is N long */ + + /* smooth each cepstral dimension separately */ + /* still to be experimented if higher order coeff can remain unsmoothed, i.e. simple copy from pdf */ + + /* reset the f0, ceps and voiced outfuffers */ + cep->outXCepReadPos = cep->outXCepWritePos = 0; + cep->outVoicedReadPos = cep->outVoicedWritePos = 0; + cep->outF0ReadPos = cep->outF0WritePos = 0; + + PICODBG_DEBUG(("smoothing %d frames\n", N)); + + /* smooth f0 */ + pdf = cep->pdflfz; + for (cepnum = 0; cepnum < pdf->ceporder; cepnum++) { + if (cep->activeEndPos <= 0) { + /* do nothing */ + } else if (3 < N) { + makeWUWandWUm(cep, pdf, cep->indicesLFZ, 0, N, + cepnum); /* update diag0, diag1, diag2, WUm */ + invMatrix(cep, N, cep->outF0 + cep->outF0WritePos, cepnum, pdf, + PICOCEP_LFZINVPOW, PICOCEP_LFZDOUBLEDEC); + } else { + getDirect(pdf, cep->indicesLFZ, cep->activeEndPos, + cepnum, cep->outF0 + cep->outF0WritePos); + } + }/* end for cepnum */ + cep->outF0WritePos += cep->activeEndPos * pdf->ceporder; + + /* smooth mgc */ + pdf = cep->pdfmgc; + for (cepnum = 0; cepnum < pdf->ceporder; cepnum++) { + if (cep->activeEndPos <= 0) { + /* do nothing */ + } else if (3 < N) { + makeWUWandWUm(cep, pdf, cep->indicesMGC, 0, N, + cepnum); /* update diag0, diag1, diag2, WUm */ + invMatrix(cep, N, cep->outXCep + + cep->outXCepWritePos, cepnum, + pdf, PICOCEP_MGCINVPOW, + PICOCEP_MGCDOUBLEDEC); + } else { + getDirect(pdf, cep->indicesMGC, cep->activeEndPos, + cepnum, cep->outXCep + cep->outXCepWritePos); + } + }/* end for cepnum */ + cep->outXCepWritePos += cep->activeEndPos * pdf->ceporder; + + getVoiced(pdf, cep->indicesMGC, cep->activeEndPos, cep->outVoiced + + cep->outVoicedWritePos); + cep->outVoicedWritePos += cep->activeEndPos; + + } + /* setting indexReadPos to the next active index to be used. (will be advanced by FRAME when + * reading the phoneId */ + cep->indexReadPos = 0; + cep->procState = PICOCEP_STEPSTATE_PROCESS_FRAME; + return PICODATA_PU_BUSY; /*data to feed*/ + + break; + + case PICOCEP_STEPSTATE_PROCESS_FRAME: + + /* *************** creating output items (type FRAME) ***********************************/ + + PICODBG_TRACE(("FRAME")); + + if ((cep->headxBottom < cep->headxWritePos) + && (cep->headx[cep->headxBottom].frame + <= cep->indexReadPos)) { + + /* output item in headx/cbuf */ + /* copy item to outBuf */ + PICODBG_DEBUG(("FRAME copy item in inBuf to outBuf")); + picodata_put_itemparts( + &(cep->headx[cep->headxBottom].head), + &(cep->cbuf[cep->headx[cep->headxBottom].cind]), + cep->headx[cep->headxBottom].head.len, cep->outBuf, + cep->outBufSize, &blen); + cep->outWritePos += blen; + /* consume item in headx/cbuf */ + PICODBG_DEBUG(("PARSE consuming item of headx/cbuf")); + cep->headxBottom++; + + /* output item and then go to parse to treat a new item. */ + cep->feedFollowState = PICOCEP_STEPSTATE_PROCESS_FRAME; + cep->procState = PICOCEP_STEPSTATE_FEED; + break; + } + + if (cep->indexReadPos < cep->activeEndPos) { + /*------------ there are frames to output ----------------------------------------*/ + /* still frames to output, create new FRAME_PAR item */ + + cep->nNumFrames++; + + PICODBG_DEBUG(("FRAME creating FRAME_PAR: active: [0,%i[, read=%i, write=%i", + cep->activeEndPos, cep->indexReadPos, cep->indexWritePos + )); + + /* create FRAME_PAR items from cep->outXX one by one */ + + /* converting the ceps shorts into floats: + * scmeanpow = pdf->bigpow - pdf->meanpow; + * for all sval: + * fval = (picoos_single) sval / scmeanpow; + */ + + cep->outWritePos = cep->outReadPos = 0; + cep->outBuf[cep->outWritePos++] = cep->framehead.type; + cep->outBuf[cep->outWritePos++] = cep->framehead.info1; + cep->outBuf[cep->outWritePos++] = cep->framehead.info2; + cep->outBuf[cep->outWritePos++] = cep->framehead.len; + + PICODBG_DEBUG(("FRAME writing position after header: %i",cep->outWritePos)); + + { + picoos_uint16 tmpUint16; + picoos_int16 tmpInt16; + picoos_uint16 i; + + /* */ + PICODBG_DEBUG(("FRAME reading phoneId[%i] = %c:",cep->indexReadPos, cep->phoneId[cep->indexReadPos])); + /* */ + + tmpUint16 + = (picoos_uint16) cep->phoneId[cep->indexReadPos]; + + picoos_mem_copy((void *) &tmpUint16, + (void *) &cep->outBuf[cep->outWritePos], + sizeof(tmpUint16)); + + cep->outWritePos += sizeof(tmpUint16); + + PICODBG_DEBUG(("FRAME writing position after phone id: %i",cep->outWritePos)); + + for (i = 0; i < cep->pdflfz->ceporder; i++) { + + tmpUint16 = (cep->outVoiced[cep->outVoicedReadPos] + & 0x01) ? cep->outF0[cep->outF0ReadPos] + : (picoos_uint16) 0; + + picoos_mem_copy((void *) &tmpUint16, + (void *) &cep->outBuf[cep->outWritePos], + sizeof(tmpUint16)); + cep->outWritePos += sizeof(tmpUint16); + + tmpUint16 + = (picoos_uint16) (cep->outVoiced[cep->outVoicedReadPos]); + picoos_mem_copy((void *) &tmpUint16, + (void *) &cep->outBuf[cep->outWritePos], + sizeof(tmpUint16)); + cep->outWritePos += sizeof(tmpUint16); + tmpUint16 + = (picoos_uint16) (cep->outF0[cep->outF0ReadPos]); + picoos_mem_copy((void *) &tmpUint16, + (void *) &cep->outBuf[cep->outWritePos], + sizeof(tmpUint16)); + cep->outWritePos += sizeof(tmpUint16); + + cep->outVoicedReadPos++; + cep->outF0ReadPos++; + } + + PICODBG_DEBUG(("FRAME writing position after f0: %i",cep->outWritePos)); + + for (i = 0; i < cep->pdfmgc->ceporder; i++) { + tmpInt16 = cep->outXCep[cep->outXCepReadPos++]; + picoos_mem_copy((void *) &tmpInt16, + (void *) &cep->outBuf[cep->outWritePos], + sizeof(tmpInt16)); + cep->outWritePos += sizeof(tmpInt16); + } + + PICODBG_DEBUG(("FRAME writing position after cepstrals: %i",cep->outWritePos)); + + tmpUint16 + = (picoos_uint16) cep->indicesMGC[cep->indexReadPos++]; + + picoos_mem_copy((void *) &tmpUint16, + (void *) &cep->outBuf[cep->outWritePos], + sizeof(tmpUint16)); + + PICODBG_DEBUG(("FRAME writing position after mgc index: %i",cep->outWritePos)); + + cep->outWritePos += sizeof(tmpUint16); + + } + /* finished to create FRAME_PAR, now output and then come back*/ + cep->feedFollowState = PICOCEP_STEPSTATE_PROCESS_FRAME; + cep->procState = PICOCEP_STEPSTATE_FEED; + + } else if (cep->sentenceEnd) { + /*------------ no more frames to output at end of sentence ----------------------------------------*/ + PICODBG_INFO(("End of sentence - Processed frames : %d", + cep->nNumFrames)); + cep->nNumFrames = 0;PICODBG_DEBUG(("FRAME no more active frames for this sentence")); + /* no frames left in this sentence*/ + /* reset for new sentence */ + initSmoothing(cep); + cep->sentenceEnd = FALSE; + cep->indexReadPos = cep->indexWritePos = 0; + cep->activeEndPos = PICOCEP_MAXWINLEN; + cep->headxBottom = cep->headxWritePos = 0; + cep->cbufWritePos = 0; + cep->procState = PICOCEP_STEPSTATE_PROCESS_PARSE; + } else { + /*------------ no more frames can be output but sentence end not reached ----------------------------------------*/ + PICODBG_DEBUG(("Maximum number of frames per sentence reached")); + cep->procState = PICOCEP_STEPSTATE_PROCESS_PARSE; + } + /*----------------------------------------------------*/ + break; + + case PICOCEP_STEPSTATE_FEED: + /* ***********************************************************************/ + /* FEED: combine input item with pos/phon pairs to output item */ + /* ***********************************************************************/ + + PICODBG_DEBUG(("FEED")); + + PICODBG_DEBUG(("FEED putting outBuf item into cb")); + + /*feeding items to PU output buffer*/ + sResult = picodata_cbPutItem(this->cbOut, cep->outBuf, + cep->outBufSize, &blen); + + if (PICO_EXC_BUF_OVERFLOW == sResult) { + /* we have to redo this item */ + PICODBG_DEBUG(("FEED got overflow, returning PICODATA_PU_OUT_FULL")); + return PICODATA_PU_OUT_FULL; + } else if (PICO_OK == sResult) { + + if (cep->outBuf[0] != 'k') { + PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG], + (picoos_uint8 *)"cep: ", + cep->outBuf, PICODATA_MAX_ITEMSIZE); + } + + *numBytesOutput += blen; + /*-------------------------*/ + /*reset the output pointers*/ + /*-------------------------*/ + if (cep->outReadPos >= cep->outWritePos) { + cep->outReadPos = 0; + cep->outWritePos = 0; + } + cep->procState = cep->feedFollowState; + PICODBG_DEBUG(("FEED ok, going back to procState %i", cep->procState)); + return PICODATA_PU_BUSY; + } else { + PICODBG_DEBUG(("FEED got exception %i when trying to output item",sResult)); + cep->procState = cep->feedFollowState; + return (picodata_step_result_t) sResult; + } + break; + + default: + /*NOT feeding items*/ + sResult = PICO_EXC_BUF_IGNORE; + break; + }/*end switch (cep->procState) */ + return PICODATA_PU_BUSY; /*check if there is more data to process after feeding*/ + + }/*end while*/ + /* we should never come here */ + return PICODATA_PU_ERROR; +}/*cepStep*/ + +/* Picocep.c end */ diff --git a/pico/lib/picocep.h b/pico/lib/picocep.h new file mode 100644 index 0000000..79a5d7c --- /dev/null +++ b/pico/lib/picocep.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picocep.h + * + * Cepstral Smoothing PU - Header file + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#ifndef PICOCEP_H_ +#define PICOCEP_H_ + +#include "picoos.h" +#include "picodata.h" +#include "picorsrc.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +/* ****************************************************************************** + * items related to the generic interface + ********************************************************************************/ +picodata_ProcessingUnit picocep_newCepUnit(picoos_MemoryManager mm, + picoos_Common common, picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, picorsrc_Voice voice); + +#ifdef __cplusplus +} +#endif + +#endif /*PICOCEP_H_*/ diff --git a/pico/lib/picoctrl.c b/pico/lib/picoctrl.c new file mode 100644 index 0000000..4754f35 --- /dev/null +++ b/pico/lib/picoctrl.c @@ -0,0 +1,840 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picoctrl.c + * + * Control PU -- Implementation + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include "picodefs.h" +#include "picoos.h" +#include "picodbg.h" +#include "picodata.h" +#include "picorsrc.h" + +/* processing unit definitions */ +#include "picotok.h" +#include "picopr.h" +#include "picowa.h" +#include "picosa.h" +#include "picoacph.h" +#include "picospho.h" +#include "picopam.h" +#include "picocep.h" +#include "picosig.h" +#if defined(PICO_DEVEL_MODE) +#include "../history/picosink.h" +#endif + +#include "picoctrl.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +/** + * @addtogroup picoctrl + * @b Control + * The "control" is a processing unit (PU) that contains and governs a sequence of sub-PUs + * (TTS processing chain). + * At each step (ctrlStep) it passes control to one of the sub-PUs (currrent PU). It may re-assign + * the role of "current PU" to another sub-PU, according to the status information returned from each PU. + */ + +/*---------------------------------------------------------- + * object : Control + * shortcut : ctrl + * derived from : picodata_ProcessingUnit + * implements a ProcessingUnit by creating and controlling + * a sequence of Processing Units (of possibly different + * implementations) exchanging data via CharBuffers + * ---------------------------------------------------------*/ +/* control sub-object */ +typedef struct ctrl_subobj { + picoos_uint8 numProcUnits; + picoos_uint8 curPU; + picoos_uint8 lastItemTypeProduced; + picodata_ProcessingUnit procUnit [PICOCTRL_MAX_PROC_UNITS]; + picodata_step_result_t procStatus [PICOCTRL_MAX_PROC_UNITS]; + picodata_CharBuffer procCbOut [PICOCTRL_MAX_PROC_UNITS]; +} ctrl_subobj_t; + +/** + * performs Control PU initialization + * @param this : pointer to Control PU + * @return PICO_OK : processing done + * @return PICO_ERR_OTHER : init error + * @callgraph + * @callergraph + */ +static pico_status_t ctrlInitialize(register picodata_ProcessingUnit this, picoos_int32 resetMode) { + register ctrl_subobj_t * ctrl; + pico_status_t status= PICO_OK; + picoos_int8 i; + + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + ctrl = (ctrl_subobj_t *) this->subObj; + ctrl->curPU = 0; + ctrl->lastItemTypeProduced=0; /*no item produced by default*/ + status = PICO_OK; + for (i = 0; i < ctrl->numProcUnits; i++) { + if (PICO_OK == status) { + status = ctrl->procUnit[i]->initialize(ctrl->procUnit[i], resetMode); + PICODBG_DEBUG(("(re-)initializing procUnit[%i] returned status %i",i, status)); + } + if (PICO_OK == status) { + status = picodata_cbReset(ctrl->procCbOut[i]); + PICODBG_DEBUG(("(re-)initializing procCbOut[%i] returned status %i",i, status)); + } + } + if (PICO_OK != status) { + picoos_emRaiseException(this->common->em,status,NULL,(picoos_char*)"problem (re-)initializing the engine"); + } + return status; +}/*ctrlInitialize*/ + + +/** + * performs one processing step + * @param this : pointer to Control PU + * @param mode : activation mode (unused) + * @param bytesOutput : number of bytes produced during this step (output) + * @return PICO_OK : processing done + * @return PICO_EXC_OUT_OF_MEM : no more memory available + * @return PICO_ERR_OTHER : other error + * @callgraph + * @callergraph + */ +static picodata_step_result_t ctrlStep(register picodata_ProcessingUnit this, + picoos_int16 mode, picoos_uint16 * bytesOutput) { + /* rules/invariants: + * - all pu's above current have status idle except possibly pu+1, which may be busy. + * (The latter is set if any pu->step produced output) + * - a pu returns idle iff its cbIn is empty and it has no more data ready for output */ + + register ctrl_subobj_t * ctrl = (ctrl_subobj_t *) this->subObj; + picodata_step_result_t status; + picoos_uint16 puBytesOutput; +#if defined(PICO_DEVEL_MODE) + picoos_uint8 btype; +#endif + + *bytesOutput = 0; + ctrl->lastItemTypeProduced=0; /*no item produced by default*/ + + /* --------------------- */ + /* do step of current pu */ + /* --------------------- */ + status = ctrl->procStatus[ctrl->curPU] = ctrl->procUnit[ctrl->curPU]->step( + ctrl->procUnit[ctrl->curPU], mode, &puBytesOutput); + + if (puBytesOutput) { + +#if defined(PICO_DEVEL_MODE) + /*store the type of item produced*/ + btype = picodata_cbGetFrontItemType(ctrl->procUnit[ctrl->curPU]->cbOut); + ctrl->lastItemTypeProduced=(picoos_uint8)btype; +#endif + + if (ctrl->curPU < ctrl->numProcUnits-1) { + /* data was output to internal PU buffers : set following pu to busy */ + ctrl->procStatus[ctrl->curPU + 1] = PICODATA_PU_BUSY; + } else { + /* data was output to caller output buffer */ + *bytesOutput = puBytesOutput; + } + } + /* recalculate state depending on pu status returned from curPU */ + switch (status) { + case PICODATA_PU_ATOMIC: + PICODBG_DEBUG(("got PICODATA_PU_ATOMIC")); + return status; + break; + + case PICODATA_PU_BUSY: + PICODBG_DEBUG(("got PICODATA_PU_BUSY")); + if ( (ctrl->curPU+1 < ctrl->numProcUnits) && (PICODATA_PU_BUSY + == ctrl->procStatus[ctrl->curPU+1])) { + ctrl->curPU++; + } + return status; + break; + + case PICODATA_PU_IDLE: + PICODBG_DEBUG(("got PICODATA_PU_IDLE")); + if ( (ctrl->curPU+1 < ctrl->numProcUnits) && (PICODATA_PU_BUSY + == ctrl->procStatus[ctrl->curPU+1])) { + /* still data to process below */ + ctrl->curPU++; + } else if (0 == ctrl->curPU) { /* all pu's are idle */ + /* nothing to do */ + } else { /* find non-idle pu above */ + PICODBG_DEBUG(( + "find non-idle pu above from pu %d with status %d", + ctrl->curPU, ctrl->procStatus[ctrl->curPU])); + while ((ctrl->curPU > 0) && (PICODATA_PU_IDLE + == ctrl->procStatus[ctrl->curPU])) { + ctrl->curPU--; + } + ctrl->procStatus[ctrl->curPU] = PICODATA_PU_BUSY; + } + PICODBG_DEBUG(("going to pu %d with status %d", + ctrl->curPU, ctrl->procStatus[ctrl->curPU])); + /*update last scheduled PU*/ + return ctrl->procStatus[ctrl->curPU]; + break; + + case PICODATA_PU_OUT_FULL: + PICODBG_DEBUG(("got PICODATA_PU_OUT_FULL")); + if (ctrl->curPU+1 < ctrl->numProcUnits) { /* let pu below empty buffer */ + ctrl->curPU++; + ctrl->procStatus[ctrl->curPU] = PICODATA_PU_BUSY; + } else { + /* nothing more to do, out_full will be returned to caller */ + } + return ctrl->procStatus[ctrl->curPU]; + break; + default: + return PICODATA_PU_ERROR; + break; + } +}/*ctrlStep*/ + +/** + * terminates Control PU + * @param this : pointer to Control PU + * @return PICO_OK : processing done + * @return PICO_ERR_OTHER : other error + * @callgraph + * @callergraph + */ +static pico_status_t ctrlTerminate(register picodata_ProcessingUnit this) { + pico_status_t status = PICO_OK; + picoos_int16 i; + register ctrl_subobj_t * ctrl; + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + ctrl = (ctrl_subobj_t *) this->subObj; + for (i = 0; i < ctrl->numProcUnits; i++) { + status = ctrl->procUnit[i]->terminate(ctrl->procUnit[i]); + PICODBG_DEBUG(("terminating procUnit[%i] returned status %i",i, status)); + if (PICO_OK != status) { + return status; + } + } + return status; +}/*ctrlTerminate*/ + +/** + * deallocates Control PU's subobject + * @param this : pointer to Control PU + * @return PICO_OK : processing done + * @return PICO_ERR_OTHER : other error + * @callgraph + * @callergraph + */ +static pico_status_t ctrlSubObjDeallocate(register picodata_ProcessingUnit this, + picoos_MemoryManager mm) { + register ctrl_subobj_t * ctrl; + picoos_int16 i; + + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + ctrl = (ctrl_subobj_t *) this->subObj; + mm = mm; /* fix warning "var not used in this function"*/ + /* deallocate members (procCbOut and procUnit) */ + for (i = ctrl->numProcUnits-1; i >= 0; i--) { + picodata_disposeProcessingUnit(this->common->mm,&ctrl->procUnit[i]); + picodata_disposeCharBuffer(this->common->mm, &ctrl->procCbOut[i]); + } + /* deallocate object itself */ + picoos_deallocate(this->common->mm, (void *) &this->subObj); + + return PICO_OK; +}/*ctrlSubObjDeallocate*/ + +/** + * inserts a new PU in the TTS processing chain + * @param this : pointer to Control PU + * @param puType : type of the PU to be inserted + * @param last : if true, inserted PU is the last in the TTS processing chain + * @return PICO_OK : processing done + * @return PICO_EXC_OUT_OF_MEM : no more memory available + * @return PICO_ERR_OTHER : other error + * @remarks Calls the PU object creation method + * @callgraph + * @callergraph + */ +static pico_status_t ctrlAddPU(register picodata_ProcessingUnit this, + picodata_putype_t puType, + picoos_bool levelAwareCbOut, + picoos_bool last) +{ + picoos_uint16 bufSize; + register ctrl_subobj_t * ctrl; + picodata_CharBuffer cbIn; + picoos_uint8 newPU; + if (this == NULL) { + return PICO_ERR_OTHER; + } + ctrl = (ctrl_subobj_t *) this->subObj; + if (ctrl == NULL) { + return PICO_ERR_OTHER; + } + newPU = ctrl->numProcUnits; + if (0 == newPU) { + PICODBG_DEBUG(("taking cbIn of this because adding first pu")); + cbIn = this->cbIn; + } else { + PICODBG_DEBUG(("taking cbIn of previous pu")); + cbIn = ctrl->procCbOut[newPU-1]; + } + if (last) { + PICODBG_DEBUG(("taking cbOut of this because adding last pu")); + ctrl->procCbOut[newPU] = this->cbOut; + } else { + PICODBG_DEBUG(("creating intermediate cbOut of pu[%i]", newPU)); + bufSize = picodata_get_default_buf_size(puType); + ctrl->procCbOut[newPU] = picodata_newCharBuffer(this->common->mm, + this->common,bufSize); + + PICODBG_DEBUG(("intermediate cbOut of pu[%i] (address %i)", newPU, + (picoos_uint32) ctrl->procCbOut[newPU])); + if (NULL == ctrl->procCbOut[newPU]) { + return PICO_EXC_OUT_OF_MEM; + } + } + ctrl->procStatus[newPU] = PICODATA_PU_IDLE; + /*...............*/ + switch (puType) { + case PICODATA_PUTYPE_TOK: + PICODBG_DEBUG(("creating TokenizeUnit for pu %i", newPU)); + ctrl->procUnit[newPU] = picotok_newTokenizeUnit(this->common->mm, + this->common, cbIn, ctrl->procCbOut[newPU], this->voice); + break; + case PICODATA_PUTYPE_PR: + PICODBG_DEBUG(("creating PreprocUnit for pu %i", newPU)); + ctrl->procUnit[newPU] = picopr_newPreprocUnit(this->common->mm, + this->common, cbIn, ctrl->procCbOut[newPU], this->voice); + break; + case PICODATA_PUTYPE_WA: + PICODBG_DEBUG(("creating WordAnaUnit for pu %i", newPU)); + ctrl->procUnit[newPU] = picowa_newWordAnaUnit(this->common->mm, + this->common, cbIn, ctrl->procCbOut[newPU], this->voice); + break; + case PICODATA_PUTYPE_SA: + PICODBG_DEBUG(("creating SentAnaUnit for pu %i", newPU)); + ctrl->procUnit[newPU] = picosa_newSentAnaUnit(this->common->mm, + this->common, cbIn, ctrl->procCbOut[newPU], this->voice); + break; + case PICODATA_PUTYPE_ACPH: + PICODBG_DEBUG(("creating AccPhrUnit for pu %i", newPU)); + ctrl->procUnit[newPU] = picoacph_newAccPhrUnit(this->common->mm, + this->common, cbIn, ctrl->procCbOut[newPU], this->voice); + break; + case PICODATA_PUTYPE_SPHO: + PICODBG_DEBUG(("creating SentPhoUnit for pu %i", newPU)); + ctrl->procUnit[newPU] = picospho_newSentPhoUnit(this->common->mm, + this->common, cbIn, ctrl->procCbOut[newPU], this->voice); + break; + case PICODATA_PUTYPE_PAM: + PICODBG_DEBUG(("creating PAMUnit for pu %i", newPU)); + ctrl->procUnit[newPU] = picopam_newPamUnit(this->common->mm, + this->common, cbIn, ctrl->procCbOut[newPU], this->voice); + break; + case PICODATA_PUTYPE_CEP: + PICODBG_DEBUG(("creating CepUnit for pu %i", newPU)); + ctrl->procUnit[newPU] = picocep_newCepUnit(this->common->mm, + this->common, cbIn, ctrl->procCbOut[newPU], this->voice); + break; +#if defined(PICO_DEVEL_MODE) + case PICODATA_PUTYPE_SINK: + PICODBG_DEBUG(("creating SigUnit for pu %i", newPU)); + ctrl->procUnit[newPU] = picosink_newSinkUnit(this->common->mm, + this->common, cbIn, ctrl->procCbOut[newPU], this->voice); + break; +#endif + case PICODATA_PUTYPE_SIG: + PICODBG_DEBUG(("creating SigUnit for pu %i", newPU)); + ctrl->procUnit[newPU] = picosig_newSigUnit(this->common->mm, + this->common, cbIn, ctrl->procCbOut[newPU], this->voice); + break; + default: + ctrl->procUnit[newPU] = picodata_newProcessingUnit( + this->common->mm, this->common, cbIn, + ctrl->procCbOut[newPU], this->voice); + break; + } + if (NULL == ctrl->procUnit[newPU]) { + picodata_disposeCharBuffer(this->common->mm,&ctrl->procCbOut[newPU]); + return PICO_EXC_OUT_OF_MEM; + } + ctrl->numProcUnits++; + return PICO_OK; +}/*ctrlAddPU*/ + +/*forward declaration : see below for full function body*/ +void picoctrl_disposeControl(picoos_MemoryManager mm, + picodata_ProcessingUnit * this); + +/** + * initializes a control PU object + * @param mm : memory manager + * @param common : the common object + * @param cbIn : the input char buffer + * @param cbOut : the output char buffer + * @param voice : the voice object + * @return the pointer to the PU object created if OK + * @return PICO_EXC_OUT_OF_MEM : no more memory available + * @return NULL otherwise + * @callgraph + * @callergraph + */ +picodata_ProcessingUnit picoctrl_newControl(picoos_MemoryManager mm, + picoos_Common common, picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, picorsrc_Voice voice) { + picoos_int16 i; + register ctrl_subobj_t * ctrl; + picodata_ProcessingUnit this = picodata_newProcessingUnit(mm, common, cbIn, + cbOut,voice); + if (this == NULL) { + return NULL; + } + + this->initialize = ctrlInitialize; + this->step = ctrlStep; + this->terminate = ctrlTerminate; + this->subDeallocate = ctrlSubObjDeallocate; + + this->subObj = picoos_allocate(mm, sizeof(ctrl_subobj_t)); + if (this->subObj == NULL) { + picoos_deallocate(mm, (void **)(void*)&this); + return NULL; + } + + ctrl = (ctrl_subobj_t *) this->subObj; + + for (i=0; i < PICOCTRL_MAX_PROC_UNITS; i++) { + ctrl->procUnit[i] = NULL; + ctrl->procStatus[i] = PICODATA_PU_IDLE; + ctrl->procCbOut[i] = NULL; + } + ctrl->numProcUnits = 0; + + if ( + (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_TOK, FALSE, /*last*/FALSE)) && + (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_PR, FALSE, FALSE)) && + (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_WA, FALSE, FALSE)) && + (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_SA, FALSE, FALSE)) && + (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_ACPH, FALSE, FALSE)) && + (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_SPHO, FALSE, FALSE)) && + (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_PAM, FALSE, FALSE)) && + (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_CEP, FALSE, FALSE)) && + (PICO_OK == ctrlAddPU(this,PICODATA_PUTYPE_SIG, FALSE, TRUE)) + ) { + + /* we don't call ctrlInitialize here because ctrlAddPU does initialize the PUs allready and the only thing + * remaining to initialize is: + */ + ctrl->curPU = 0; + return this; + } else { + picoctrl_disposeControl(this->common->mm,&this); + return NULL; + } + +}/*picoctrl_newControl*/ + +/** + * disposes a Control PU + * @param mm : memory manager + * @param this : pointer to Control PU + * + * @return void + * @callgraph + * @callergraph + */ +void picoctrl_disposeControl(picoos_MemoryManager mm, + picodata_ProcessingUnit * this) +{ + picodata_disposeProcessingUnit(mm, this); +}/*picoctrl_disposeControl*/ + +/* ************************************************************************** + * + * Engine + * + ****************************************************************************/ +/** object : Engine + * shortcut : eng + */ +typedef struct picoctrl_engine { + picoos_uint32 magic; /* magic number used to validate handles */ + void *raw_mem; + picoos_Common common; + picorsrc_Voice voice; + picodata_ProcessingUnit control; + picodata_CharBuffer cbIn, cbOut; +} picoctrl_engine_t; + + +#define MAGIC_MASK 0x5069436F /* PiCo */ + +#define SET_MAGIC_NUMBER(eng) \ + (eng)->magic = ((picoos_uint32) (uintptr_t) (eng)) ^ MAGIC_MASK + +#define CHECK_MAGIC_NUMBER(eng) \ + ((eng)->magic == (((picoos_uint32) (uintptr_t) (eng)) ^ MAGIC_MASK)) + +/** + * performs an engine reset + * @param this : the engine object + * @return PICO_OK : reset performed + * @return otherwise error code + * @callgraph + * @callergraph + */ +pico_status_t picoctrl_engReset(picoctrl_Engine this, picoos_int32 resetMode) +{ + pico_status_t status; + + if (NULL == this) { + return PICO_ERR_NULLPTR_ACCESS; + } + picoos_emReset(this->common->em); + + status = this->control->terminate(this->control); + if (PICO_OK == status) { + status = this->control->initialize(this->control, resetMode); + } + if (PICO_OK == status) { + status = picodata_cbReset(this->cbIn); + } + if (PICO_OK == status) { + status = picodata_cbReset(this->cbOut); + } + if (PICO_OK != status) { + picoos_emRaiseException(this->common->em,status,NULL,(picoos_char*) "problem resetting engine"); + } + return status; +} + +/** + * checks an engine handle + * @param this : the engine object + * @return PICO_OK : reset performed + * @return non-zero if 'this' is a valid engine handle + * @return zero otherwise + * @callgraph + * @callergraph + */ +picoos_int16 picoctrl_isValidEngineHandle(picoctrl_Engine this) +{ + return (this != NULL) && CHECK_MAGIC_NUMBER(this); +}/*picoctrl_isValidEngineHandle*/ + +/** + * creates a new engine object + * @param mm : memory manager to be used for this engine + * @param rm : resource manager to be used for this engine + * @param voiceName : voice definition to be used for this engine + * @return PICO_OK : reset performed + * @return new engine handle + * @return NULL otherwise + * @callgraph + * @callergraph + */ +picoctrl_Engine picoctrl_newEngine(picoos_MemoryManager mm, + picorsrc_ResourceManager rm, const picoos_char * voiceName) { + picoos_uint8 done= TRUE; + + picoos_uint16 bSize; + + picoos_MemoryManager engMM; + picoos_ExceptionManager engEM; + + picoctrl_Engine this = (picoctrl_Engine) picoos_allocate(mm, sizeof(*this)); + + PICODBG_DEBUG(("creating engine for voice '%s'",voiceName)); + + done = (NULL != this); + + if (done) { + this->magic = 0; + this->common = NULL; + this->voice = NULL; + this->control = NULL; + this->cbIn = NULL; + this->cbOut = NULL; + + this->raw_mem = picoos_allocate(mm, PICOCTRL_DEFAULT_ENGINE_SIZE); + if (NULL == this->raw_mem) { + done = FALSE; + } + } + + if (done) { + engMM = picoos_newMemoryManager(this->raw_mem, PICOCTRL_DEFAULT_ENGINE_SIZE, + /*enableMemProt*/ FALSE); + done = (NULL != engMM); + } + if (done) { + this->common = picoos_newCommon(engMM); + engEM = picoos_newExceptionManager(engMM); + done = (NULL != this->common) && (NULL != engEM); + } + if (done) { + this->common->mm = engMM; + this->common->em = engEM; + + done = (PICO_OK == picorsrc_createVoice(rm,voiceName,&(this->voice))); + } + if (done) { + bSize = picodata_get_default_buf_size(PICODATA_PUTYPE_TEXT); + + this->cbIn = picodata_newCharBuffer(this->common->mm, + this->common, bSize); + bSize = picodata_get_default_buf_size(PICODATA_PUTYPE_SIG); + + this->cbOut = picodata_newCharBuffer(this->common->mm, + this->common, bSize); + + PICODBG_DEBUG(("cbOut has address %i", (picoos_uint32) this->cbOut)); + + + this->control = picoctrl_newControl(this->common->mm, this->common, + this->cbIn, this->cbOut, this->voice); + done = (NULL != this->cbIn) && (NULL != this->cbOut) + && (NULL != this->control); + } + if (done) { + SET_MAGIC_NUMBER(this); + } else { + if (NULL != this) { + if (NULL != this->voice) { + picorsrc_releaseVoice(rm,&(this->voice)); + } + if(NULL != this->raw_mem) { + picoos_deallocate(mm,&(this->raw_mem)); + } + picoos_deallocate(mm,(void *)&this); + } + } + return this; +}/*picoctrl_newEngine*/ + +/** + * disposes an engine object + * @param mm : memory manager associated to the engine + * @param rm : resource manager associated to the engine + * @param this : handle of the engine to dispose + * @return PICO_OK : reset performed + * @return void + * @callgraph + * @callergraph + */ +void picoctrl_disposeEngine(picoos_MemoryManager mm, picorsrc_ResourceManager rm, + picoctrl_Engine * this) +{ + if (NULL != (*this)) { + if (NULL != (*this)->voice) { + picorsrc_releaseVoice(rm,&((*this)->voice)); + } + if(NULL != (*this)->control) { + picoctrl_disposeControl((*this)->common->mm,&((*this)->control)); + } + if(NULL != (*this)->raw_mem) { + picoos_deallocate(mm,&((*this)->raw_mem)); + } + (*this)->magic ^= 0xFFFEFDFC; + picoos_deallocate(mm,(void **)this); + } +}/*picoctrl_disposeEngine*/ + +/** + * resets the exception manager of an engine + * @param this : handle of the engine + * @return void + * @callgraph + * @callergraph + */ +void picoctrl_engResetExceptionManager( + picoctrl_Engine this + ) +{ + picoos_emReset(this->common->em); +}/*picoctrl_engResetExceptionManager*/ + +/** + * returns the engine common pointer + * @param this : handle of the engine + * @return PICO_OK : reset performed + * @return the engine common pointer + * @return NULL if error + * @callgraph + * @callergraph + */ +picoos_Common picoctrl_engGetCommon(picoctrl_Engine this) { + if (NULL == this) { + return NULL; + } else { + return this->common; + } +}/*picoctrl_engGetCommon*/ + +/** + * feed raw 'text' into 'engine'. text may contain '\\0'. + * @param this : handle of the engine + * @param text : the input text + * @param textSize : size of the input text + * @param *bytesPut : the number of bytes effectively consumed from 'text'. + * @return PICO_OK : feeding succeded + * @return PICO_ERR_OTHER : if error + * @callgraph + * @callergraph + */ +pico_status_t picoctrl_engFeedText(picoctrl_Engine this, + picoos_char * text, + picoos_int16 textSize, picoos_int16 * bytesPut) { + if (NULL == this) { + return PICO_ERR_OTHER; + } + PICODBG_DEBUG(("get \"%.100s\"", text)); + *bytesPut = 0; + while ((*bytesPut < textSize) && (PICO_OK == picodata_cbPutCh(this->cbIn, text[*bytesPut]))) { + (*bytesPut)++; + } + + return PICO_OK; +}/*picoctrl_engFeedText*/ + +/** + * gets engine output bytes + * @param this : handle of the engine + * @param buffer : the destination buffer + * @param bufferSize : max size of the destinatioon buffer + * @param *bytesReceived : the number of bytes effectively returned + * @return PICO_OK : feeding succeded + * @return PICO_ERR_OTHER : if error + * @callgraph + * @callergraph + */ +picodata_step_result_t picoctrl_engFetchOutputItemBytes( + picoctrl_Engine this, + picoos_char *buffer, + picoos_int16 bufferSize, + picoos_int16 *bytesReceived) { + picoos_uint16 ui; + picodata_step_result_t stepResult; + pico_status_t rv; + + if (NULL == this) { + return (picodata_step_result_t)PICO_STEP_ERROR; + } + PICODBG_DEBUG(("doing one step")); + stepResult = this->control->step(this->control,/* mode */0,&ui); + if (PICODATA_PU_ERROR != stepResult) { + PICODBG_TRACE(("filling output buffer")); + rv = picodata_cbGetSpeechData(this->cbOut, (picoos_uint8 *)buffer, + bufferSize, &ui); + + if (ui > 255) { /* because picoapi uses signed int16 */ + return (picodata_step_result_t)PICO_STEP_ERROR; + } else { + *bytesReceived = ui; + } + if ((rv == PICO_EXC_BUF_UNDERFLOW) || (rv == PICO_EXC_BUF_OVERFLOW)) { + PICODBG_ERROR(("problem getting speech data")); + return (picodata_step_result_t)PICO_STEP_ERROR; + } + /* rv must now be PICO_OK or PICO_EOF */ + PICODBG_ASSERT(((PICO_EOF == rv) || (PICO_OK == rv))); + if ((PICODATA_PU_IDLE == stepResult) && (PICO_EOF == rv)) { + PICODBG_DEBUG(("IDLE")); + return (picodata_step_result_t)PICO_STEP_IDLE; + } else if (PICODATA_PU_ERROR == stepResult) { + PICODBG_DEBUG(("ERROR")); + return (picodata_step_result_t)PICO_STEP_ERROR; + } else { + PICODBG_DEBUG(("BUSY")); + return (picodata_step_result_t)PICO_STEP_BUSY; + } + } else { + return (picodata_step_result_t)PICO_STEP_ERROR; + } +}/*picoctrl_engFetchOutputItemBytes*/ + +/** + * returns the last scheduled PU + * @param this : handle of the engine + * @return a value >= 0 : last scheduled PU index + * @remarks designed to be used for performance evaluation + * @callgraph + * @callergraph + */ +picodata_step_result_t picoctrl_getLastScheduledPU( + picoctrl_Engine this + ) +{ + ctrl_subobj_t * ctrl; + if (NULL == this || NULL == this->control->subObj) { + return PICO_ERR_OTHER; + } + ctrl = (ctrl_subobj_t *) ((*this).control->subObj); + return (picodata_step_result_t) ctrl->curPU; +}/*picoctrl_getLastScheduledPU*/ + +/** + * returns the last item type produced by the last scheduled PU + * @param this : handle of the engine + * @return a value >= 0 : item type (see picodata.h for item types) + * @return a value = 0 : no item produced + * @remarks designed to be used for performance evaluation + * @callgraph + * @callergraph + */ +picodata_step_result_t picoctrl_getLastProducedItemType( + picoctrl_Engine this + ) +{ + ctrl_subobj_t * ctrl; + if (NULL == this || NULL == this->control->subObj) { + return PICO_ERR_OTHER; + } + ctrl = (ctrl_subobj_t *) ((*this).control->subObj); + return (picodata_step_result_t) ctrl->lastItemTypeProduced; +}/*picoctrl_getLastProducedItemType*/ + + +#ifdef __cplusplus +} +#endif + +/* Picoctrl.c end */ diff --git a/pico/lib/picoctrl.h b/pico/lib/picoctrl.h new file mode 100644 index 0000000..f7b9b6e --- /dev/null +++ b/pico/lib/picoctrl.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picoctrl.h + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#ifndef PICOCTRL_H_ +#define PICOCTRL_H_ + +#include "picodefs.h" +#include "picoos.h" +#include "picorsrc.h" +#include "picodata.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +#define PICOCTRL_MAX_PROC_UNITS 25 + +/* temporarily increased for preprocessing +#define PICOCTRL_DEFAULT_ENGINE_SIZE 200000 +*/ +#define PICOCTRL_DEFAULT_ENGINE_SIZE 1000000 + +typedef struct picoctrl_engine * picoctrl_Engine; + +picoos_int16 picoctrl_isValidEngineHandle(picoctrl_Engine this); + +picoctrl_Engine picoctrl_newEngine ( + picoos_MemoryManager mm, + picorsrc_ResourceManager rm, + const picoos_char * voiceName + ); + +void picoctrl_disposeEngine( + picoos_MemoryManager mm, + picorsrc_ResourceManager rm, + picoctrl_Engine * this + ); + +pico_status_t picoctrl_engFeedText( + picoctrl_Engine engine, + picoos_char * text, + picoos_int16 textSize, + picoos_int16 * bytesPut); + +pico_status_t picoctrl_engReset( + picoctrl_Engine engine, + picoos_int32 resetMode); + +picoos_Common picoctrl_engGetCommon(picoctrl_Engine this); + +picodata_step_result_t picoctrl_engFetchOutputItemBytes( + picoctrl_Engine engine, + picoos_char * buffer, + picoos_int16 bufferSize, + picoos_int16 * bytesReceived +); + +void picoctrl_engResetExceptionManager( + picoctrl_Engine this + ); + + +picodata_step_result_t picoctrl_getLastScheduledPU( + picoctrl_Engine engine + ); + +picodata_step_result_t picoctrl_getLastProducedItemType( + picoctrl_Engine engine + ); + +#ifdef __cplusplus +} +#endif + +#endif /*PICOCTRL_H_*/ diff --git a/pico/lib/picodata.c b/pico/lib/picodata.c new file mode 100644 index 0000000..4878987 --- /dev/null +++ b/pico/lib/picodata.c @@ -0,0 +1,1155 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picodata.c + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include "picodefs.h" +#include "picoos.h" +#include "picodbg.h" +#include "picorsrc.h" +#include "picotrns.h" +#include "picodata.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +/* we output coefficients as fixed point values */ +#define PICOCEP_OUT_DATA_FORMAT PICODATA_ITEMINFO1_FRAME_PAR_DATA_FORMAT_FIXED + +/* *************************************************************** + * CharBuffer * + *****************************************************************/ + +/* + * method signatures + */ +typedef pico_status_t (* picodata_cbPutItemMethod) (register picodata_CharBuffer this, + const picoos_uint8 *buf, const picoos_uint16 blenmax, + picoos_uint16 *blen); + +typedef pico_status_t (* picodata_cbGetItemMethod) (register picodata_CharBuffer this, + picoos_uint8 *buf, const picoos_uint16 blenmax, + picoos_uint16 *blen, const picoos_uint8 issd); + +typedef pico_status_t (* picodata_cbSubResetMethod) (register picodata_CharBuffer this); +typedef pico_status_t (* picodata_cbSubDeallocateMethod) (register picodata_CharBuffer this, picoos_MemoryManager mm); + +typedef struct picodata_char_buffer +{ + picoos_char *buf; + picoos_uint16 rear; /* next free position to write */ + picoos_uint16 front; /* next position to read */ + picoos_uint16 len; /* empty: len = 0, full: len = size */ + picoos_uint16 size; + + picoos_Common common; + + picodata_cbGetItemMethod getItem; + picodata_cbPutItemMethod putItem; + + picodata_cbSubResetMethod subReset; + picodata_cbSubDeallocateMethod subDeallocate; + void * subObj; +} char_buffer_t; + + +static pico_status_t data_cbPutItem(register picodata_CharBuffer this, + const picoos_uint8 *buf, const picoos_uint16 blenmax, + picoos_uint16 *blen); + +static pico_status_t data_cbGetItem(register picodata_CharBuffer this, + picoos_uint8 *buf, const picoos_uint16 blenmax, + picoos_uint16 *blen, const picoos_uint8 issd); + +pico_status_t picodata_cbReset(register picodata_CharBuffer this) +{ + this->rear = 0; + this->front = 0; + this->len = 0; + if (NULL != this->subObj) { + return this->subReset(this); + } else { + return PICO_OK; + } +} + +/* CharBuffer constructor */ +picodata_CharBuffer picodata_newCharBuffer(picoos_MemoryManager mm, + picoos_Common common, + picoos_objsize_t size) +{ + picodata_CharBuffer this; + + this = (picodata_CharBuffer) picoos_allocate(mm, sizeof(*this)); + PICODBG_DEBUG(("new character buffer, size=%i", size)); + if (NULL == this) { + return NULL; + } + this->buf = picoos_allocate(mm, size); + if (NULL == this->buf) { + picoos_deallocate(mm, (void*) &this); + return NULL; + } + this->size = size; + this->common = common; + + this->getItem = data_cbGetItem; + this->putItem = data_cbPutItem; + + this->subReset = NULL; + this->subDeallocate = NULL; + this->subObj = NULL; + + picodata_cbReset(this); + return this; +} + +void picodata_disposeCharBuffer(picoos_MemoryManager mm, + picodata_CharBuffer *this) +{ + if (NULL != (*this)) { + /* terminate */ + if (NULL != (*this)->subObj) { + (*this)->subDeallocate(*this,mm); + } + picoos_deallocate(mm,(void*)&(*this)->buf); + picoos_deallocate(mm,(void*)this); + } +} + +pico_status_t picodata_cbPutCh(register picodata_CharBuffer this, + picoos_char ch) +{ + if (this->len < this->size) { + this->buf[this->rear++] = ch; + this->rear %= this->size; + this->len++; + return PICO_OK; + } else { + return PICO_EXC_BUF_OVERFLOW; + } +} + + +picoos_int16 picodata_cbGetCh(register picodata_CharBuffer this) +{ + picoos_char ch; + if (this->len > 0) { + ch = this->buf[this->front++]; + this->front %= this->size; + this->len--; + return ch; + } else { + return PICO_EOF; + } +} + +/* *************************************************************** + * items: CharBuffer functions * + *****************************************************************/ + +static pico_status_t data_cbGetItem(register picodata_CharBuffer this, + picoos_uint8 *buf, const picoos_uint16 blenmax, + picoos_uint16 *blen, const picoos_uint8 issd) +{ + picoos_uint16 i; + + if (this->len < PICODATA_ITEM_HEADSIZE) { /* item not in cb? */ + *blen = 0; + if (this->len == 0) { /* is cb empty? */ + PICODBG_DEBUG(("no item to get")); + return PICO_EOF; + } else { /* cb not empty, but not a valid item */ + PICODBG_WARN(("problem getting item, incomplete head, underflow")); + } + return PICO_EXC_BUF_UNDERFLOW; + } + *blen = PICODATA_ITEM_HEADSIZE + (picoos_uint8)(this->buf[((this->front) + + PICODATA_ITEMIND_LEN) % this->size]); + + /* if getting speech data in item */ + if (issd) { + /* check item type */ + if (this->buf[this->front] != PICODATA_ITEM_FRAME) { + PICODBG_WARN(("item type mismatch for speech data: %c", + this->buf[this->front])); + for (i=0; i<*blen; i++) { + this->front++; + this->front %= this->size; + this->len--; + } + *blen = 0; + return PICO_OK; + } + } + + if (*blen > this->len) { /* item in cb not complete? */ + PICODBG_WARN(("problem getting item, incomplete content, underflow; " + "blen=%d, len=%d", *blen, this->len)); + *blen = 0; + return PICO_EXC_BUF_UNDERFLOW; + } + if (blenmax < *blen) { /* buf not large enough? */ + PICODBG_WARN(("problem getting item, overflow")); + *blen = 0; + return PICO_EXC_BUF_OVERFLOW; + } + + /* if getting speech data in item */ + if (issd) { + /* skip item header */ + for (i = 0; i < PICODATA_ITEM_HEADSIZE; i++) { + this->front++; + this->front %= this->size; + this->len--; + } + *blen -= PICODATA_ITEM_HEADSIZE; + } + + /* all ok, now get item (or speech data only) */ + for (i = 0; i < *blen; i++) { + buf[i] = (picoos_uint8)(this->buf[this->front++]); + this->front %= this->size; + this->len--; + } + +#if defined(PICO_DEBUG) + if (issd) { + PICODBG_DEBUG(("got speech data: %d samples", *blen)); + } else { + PICODBG_DEBUG(("got item: %c|%d|%d|%d||", buf[PICODATA_ITEMIND_TYPE], + buf[PICODATA_ITEMIND_INFO1], buf[PICODATA_ITEMIND_INFO2], + buf[PICODATA_ITEMIND_LEN])); + for (i=PICODATA_ITEM_HEADSIZE; i<*blen; i++) { + if (buf[PICODATA_ITEMIND_TYPE] == PICODATA_ITEM_WORDGRAPH) { + PICODBG_DEBUG(("%c", buf[i])); + } else { + PICODBG_DEBUG((" %d", buf[i])); + } + } + } +#endif + + return PICO_OK; +} + +static pico_status_t data_cbPutItem(register picodata_CharBuffer this, + const picoos_uint8 *buf, const picoos_uint16 blenmax, + picoos_uint16 *blen) +{ + picoos_uint16 i; + + if (blenmax < PICODATA_ITEM_HEADSIZE) { /* itemlen not accessible? */ + PICODBG_WARN(("problem putting item, underflow")); + *blen = 0; + return PICO_EXC_BUF_UNDERFLOW; + } + *blen = buf[PICODATA_ITEMIND_LEN] + PICODATA_ITEM_HEADSIZE; + if (*blen > (this->size - this->len)) { /* cb not enough space? */ + PICODBG_WARN(("problem putting item, overflow")); + *blen = 0; + return PICO_EXC_BUF_OVERFLOW; + } + if (*blen > blenmax) { /* item in buf not completely accessible? */ + PICODBG_WARN(("problem putting item, underflow")); + *blen = 0; + return PICO_EXC_BUF_UNDERFLOW; + } + /* all ok, now put complete item */ + +#if defined(PICO_DEBUG) + PICODBG_DEBUG(("putting item: %c|%d|%d|%d||", + buf[PICODATA_ITEMIND_TYPE], + buf[PICODATA_ITEMIND_INFO1], + buf[PICODATA_ITEMIND_INFO2], + buf[PICODATA_ITEMIND_LEN])); + for (i=PICODATA_ITEM_HEADSIZE; i<*blen; i++) { + if (buf[PICODATA_ITEMIND_TYPE] == PICODATA_ITEM_WORDGRAPH) { + PICODBG_DEBUG(("%c", buf[i])); + } else { + PICODBG_DEBUG((" %d", buf[i])); + } + } +#endif + + for (i = 0; i < *blen; i++) { + /* put single byte */ + this->buf[this->rear++] = (picoos_char)buf[i]; + this->rear %= this->size; + this->len++; + } + return PICO_OK; +} + +/*---------------------------------------------------------- + * Names : picodata_cbGetItem + * picodata_cbGetSpeechData + * Function: gets one item from 'this' and writes it on 'blenmax' sized 'buf'. + * gets one item from 'this' and writes the speech data to + * 'blenmax' sized 'buf'. + * Returns : PICO_OK : one item was copied + * PICO_EOF : 'this' is empty; no new items available + * PICO_BUF_UNDERFLOW : 'this' doesn't contain a full/valid item + * PICO_BUF_OVERFLOW : 'buf[blenmax]' too small to hold item + * on return, '*blen' contains the number of bytes written to 'buf' + * ---------------------------------------------------------*/ +pico_status_t picodata_cbGetItem(register picodata_CharBuffer this, + picoos_uint8 *buf, const picoos_uint16 blenmax, + picoos_uint16 *blen) +{ + return this->getItem(this, buf, blenmax, blen, FALSE); +} + +pico_status_t picodata_cbGetSpeechData(register picodata_CharBuffer this, + picoos_uint8 *buf, const picoos_uint16 blenmax, + picoos_uint16 *blen) +{ + + return this->getItem(this, buf, blenmax, blen, TRUE); +} + + +pico_status_t picodata_cbPutItem(register picodata_CharBuffer this, + const picoos_uint8 *buf, const picoos_uint16 blenmax, + picoos_uint16 *blen) +{ + + return this->putItem(this,buf,blenmax,blen); +} + +/* unsafe, just for measuring purposes */ +picoos_uint8 picodata_cbGetFrontItemType(register picodata_CharBuffer this) +{ + return this->buf[this->front]; +} +/* *************************************************************** + * items: support function * + *****************************************************************/ + +picoos_uint8 is_valid_itemtype(const picoos_uint8 ch) { + switch (ch) { + case PICODATA_ITEM_WSEQ_GRAPH: + case PICODATA_ITEM_TOKEN: + case PICODATA_ITEM_WORDGRAPH: + case PICODATA_ITEM_WORDINDEX: + case PICODATA_ITEM_WORDPHON: + case PICODATA_ITEM_SYLLPHON: + case PICODATA_ITEM_BOUND: + case PICODATA_ITEM_PUNC: + case PICODATA_ITEM_CMD: + case PICODATA_ITEM_PHONE: + case PICODATA_ITEM_FRAME: + case PICODATA_ITEM_FRAME_PAR: + return TRUE; + break; + case PICODATA_ITEM_OTHER: + default: + break; + } + PICODBG_WARN(("item type problem: %c", ch)); + return FALSE; +} + +picoos_uint8 picodata_is_valid_itemhead(const picodata_itemhead_t *head) { + if ((NULL != head) && is_valid_itemtype(head->type)) { + return TRUE; + } else { + PICODBG_WARN(("item header problem")); + return FALSE; + } +} + +/* ***************************************************/ + + +pico_status_t picodata_get_itemparts_nowarn( + const picoos_uint8 *buf, const picoos_uint16 blenmax, + picodata_itemhead_t *head, picoos_uint8 *content, + const picoos_uint16 clenmax, picoos_uint16 *clen) +{ + if (blenmax >= PICODATA_ITEM_HEADSIZE) { + head->type = buf[PICODATA_ITEMIND_TYPE]; + head->info1 = buf[PICODATA_ITEMIND_INFO1]; + head->info2 = buf[PICODATA_ITEMIND_INFO2]; + head->len = buf[PICODATA_ITEMIND_LEN]; + *clen = head->len; + if (blenmax >= (*clen + PICODATA_ITEM_HEADSIZE)) { + if (clenmax >= head->len) { + picoos_uint16 i; + for (i=0; ilen; i++) { + content[i] = buf[PICODATA_ITEM_HEADSIZE+i]; + } + return PICO_OK; + } + *clen = 0; + return PICO_EXC_BUF_OVERFLOW; + } + } + *clen = 0; + return PICO_EXC_BUF_UNDERFLOW; +} + +pico_status_t picodata_get_itemparts( + const picoos_uint8 *buf, const picoos_uint16 blenmax, + picodata_itemhead_t *head, picoos_uint8 *content, + const picoos_uint16 clenmax, picoos_uint16 *clen) +{ + pico_status_t status = picodata_get_itemparts_nowarn(buf,blenmax,head,content,clenmax,clen); + if (PICO_EXC_BUF_OVERFLOW == status) { + PICODBG_WARN(("problem getting item, overflow")); + } else if (PICO_EXC_BUF_UNDERFLOW == status) { + PICODBG_WARN(("problem getting item, overflow")); + } + return status; +} +pico_status_t picodata_put_itemparts(const picodata_itemhead_t *head, + const picoos_uint8 *content, const picoos_uint16 clenmax, + picoos_uint8 *buf, const picoos_uint16 blenmax, picoos_uint16 *blen) +{ + *blen = head->len + PICODATA_ITEM_HEADSIZE; + if (blenmax >= *blen) { + if (clenmax >= head->len) { + picoos_uint16 i; + buf[PICODATA_ITEMIND_TYPE] = head->type; + buf[PICODATA_ITEMIND_INFO1] = head->info1; + buf[PICODATA_ITEMIND_INFO2] = head->info2; + buf[PICODATA_ITEMIND_LEN] = head->len; + for (i=0; ilen; i++) { + buf[PICODATA_ITEM_HEADSIZE+i] = content[i]; + } + return PICO_OK; + } + PICODBG_WARN(("problem putting item, underflow")); + *blen = 0; + return PICO_EXC_BUF_UNDERFLOW; + } + PICODBG_WARN(("problem putting item, overflow")); + *blen = 0; + return PICO_EXC_BUF_OVERFLOW; +} + +pico_status_t picodata_get_iteminfo( + picoos_uint8 *buf, const picoos_uint16 blenmax, + picodata_itemhead_t *head, picoos_uint8 **content) { + if (blenmax >= PICODATA_ITEM_HEADSIZE) { + head->type = buf[PICODATA_ITEMIND_TYPE]; + head->info1 = buf[PICODATA_ITEMIND_INFO1]; + head->info2 = buf[PICODATA_ITEMIND_INFO2]; + head->len = buf[PICODATA_ITEMIND_LEN]; + if (head->len == 0) { + *content = NULL; + } else { + *content = &buf[PICODATA_ITEM_HEADSIZE]; + } + return PICO_OK; + } + return PICO_EXC_BUF_UNDERFLOW; +} + +pico_status_t picodata_copy_item(const picoos_uint8 *inbuf, + const picoos_uint16 inlenmax, picoos_uint8 *outbuf, + const picoos_uint16 outlenmax, picoos_uint16 *numb) +{ + if (picodata_is_valid_item(inbuf, inlenmax)) { + *numb = PICODATA_ITEM_HEADSIZE + inbuf[PICODATA_ITEMIND_LEN]; + } else { + *numb = 0; + } + if (*numb > 0) { + if (outlenmax >= inlenmax) { + picoos_uint16 i; + for (i=0; i<*numb; i++) { + outbuf[i] = inbuf[i]; + } + return PICO_OK; + } else { + PICODBG_WARN(("buffer problem, out: %d > in: %d", outlenmax, inlenmax)); + *numb = 0; + return PICO_EXC_BUF_OVERFLOW; + } + } else { + PICODBG_WARN(("item problem in inbuf")); + return PICO_ERR_OTHER; + } +} + +pico_status_t picodata_set_iteminfo1(picoos_uint8 *buf, + const picoos_uint16 blenmax, const picoos_uint8 info) { + if (PICODATA_ITEMIND_INFO1 < blenmax) { + buf[PICODATA_ITEMIND_INFO1] = info; + return PICO_OK; + } else + return PICO_EXC_BUF_UNDERFLOW; +} + +pico_status_t picodata_set_iteminfo2(picoos_uint8 *buf, + const picoos_uint16 blenmax, const picoos_uint8 info) { + if (PICODATA_ITEMIND_INFO2 < blenmax) { + buf[PICODATA_ITEMIND_INFO2] = info; + return PICO_OK; + } else + return PICO_EXC_BUF_UNDERFLOW; +} + +/* sets the len field in the header contained in the item in buf; + return values: + PICO_OK <- all ok + PICO_EXC_BUF_UNDERFLOW <- underflow in buf +*/ +pico_status_t picodata_set_itemlen(picoos_uint8 *buf, + const picoos_uint16 blenmax, const picoos_uint8 len) { + if (PICODATA_ITEMIND_LEN < blenmax) { + buf[PICODATA_ITEMIND_LEN] = len; + return PICO_OK; + } else + return PICO_EXC_BUF_UNDERFLOW; +} + +picoos_uint8 picodata_is_valid_item(const picoos_uint8 *item, + const picoos_uint16 ilenmax) +{ + if (ilenmax >= PICODATA_ITEM_HEADSIZE) { + picodata_itemhead_t head; + head.type = item[0]; + head.info1 = item[1]; + head.info2 = item[2]; + head.len = item[3]; + if ((ilenmax >= (head.len + PICODATA_ITEM_HEADSIZE)) && + picodata_is_valid_itemhead(&head)) + { + return TRUE; + } + } + return FALSE; +} + +/* *************************************************************** + * ProcessingUnit * + *****************************************************************/ +picoos_uint16 picodata_get_default_buf_size (picodata_putype_t puType) +{ + return (PICODATA_PUTYPE_TEXT == puType) ? PICODATA_BUFSIZE_TEXT + : (PICODATA_PUTYPE_TOK == puType) ? PICODATA_BUFSIZE_TOK + : (PICODATA_PUTYPE_PR == puType) ? PICODATA_BUFSIZE_PR + : (PICODATA_PUTYPE_PR == puType) ? PICODATA_BUFSIZE_PR + : (PICODATA_PUTYPE_WA == puType) ? PICODATA_BUFSIZE_WA + : (PICODATA_PUTYPE_SA == puType) ? PICODATA_BUFSIZE_SA + : (PICODATA_PUTYPE_ACPH == puType) ? PICODATA_BUFSIZE_ACPH + : (PICODATA_PUTYPE_SPHO == puType) ? PICODATA_BUFSIZE_SPHO + : (PICODATA_PUTYPE_PAM == puType) ? PICODATA_BUFSIZE_PAM + : (PICODATA_PUTYPE_CEP == puType) ? PICODATA_BUFSIZE_CEP + : (PICODATA_PUTYPE_SIG == puType) ? PICODATA_BUFSIZE_SIG + : (PICODATA_PUTYPE_SINK == puType) ? PICODATA_BUFSIZE_SINK + : PICODATA_BUFSIZE_DEFAULT; +} + + +typedef struct simple_pu_data +{ + picorsrc_Voice voice; +} simple_pu_data_t; + +static pico_status_t puSimpleInitialize (register picodata_ProcessingUnit this, picoos_int32 resetMode) { + return PICO_OK; +} + +static pico_status_t puSimpleTerminate (register picodata_ProcessingUnit this) { + return PICO_OK; +} + +static picodata_step_result_t puSimpleStep (register picodata_ProcessingUnit this, + picoos_int16 mode, + picoos_uint16 * numBytesOutput) { + picoos_int16 ch; + picoos_int16 result = PICO_OK; + mode = mode; /*PP 13.10.08 : fix warning "var not used in this function"*/ + *numBytesOutput = 0; + while ((result == PICO_OK) && (ch = picodata_cbGetCh(this->cbIn)) != PICO_EOF) { + result = picodata_cbPutCh(this->cbOut,(picoos_char) ch); + (*numBytesOutput)++; + } + if (PICO_OK != result) { + (*numBytesOutput)--; + } + if (PICO_OK == result) { + return PICODATA_PU_IDLE; + } else { + return PICODATA_PU_ERROR; + } +} + + +picodata_ProcessingUnit picodata_newProcessingUnit( + picoos_MemoryManager mm, + picoos_Common common, + picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, + picorsrc_Voice voice) +{ + picodata_ProcessingUnit this = (picodata_ProcessingUnit) picoos_allocate(mm, sizeof(*this)); + if (this == NULL) { + picoos_emRaiseException(common->em,PICO_EXC_OUT_OF_MEM,NULL,NULL); + return NULL; + } + this->common = common; + this->cbIn = cbIn; + this->cbOut = cbOut; + this->voice = voice; + this->initialize = puSimpleInitialize; + this->terminate = puSimpleTerminate; + this->step = puSimpleStep; + this->subDeallocate = NULL; + this->subObj = NULL; + return this; +} + +void picodata_disposeProcessingUnit( + picoos_MemoryManager mm, + picodata_ProcessingUnit * this) +{ + if (NULL != (*this)) { + /* terminate */ + if (NULL != (*this)->subObj) { + (*this)->subDeallocate(*this,mm); + } + picoos_deallocate(mm,(void *)this); + } + +} + + +picodata_CharBuffer picodata_getCbIn(picodata_ProcessingUnit this) +{ + if (NULL == this) { + picoos_emRaiseException(this->common->em,PICO_ERR_NULLPTR_ACCESS,NULL,NULL); + return NULL; + } else { + return this->cbIn; + } +} + +picodata_CharBuffer picodata_getCbOut(picodata_ProcessingUnit this) +{ + if (NULL == this) { + picoos_emRaiseException(this->common->em,PICO_ERR_NULLPTR_ACCESS,NULL,NULL); + return NULL; + } else { + return this->cbOut; + } +} + +pico_status_t picodata_setCbIn(picodata_ProcessingUnit this, picodata_CharBuffer cbIn) +{ + if (NULL == this) { + picoos_emRaiseException(this->common->em,PICO_ERR_NULLPTR_ACCESS,NULL,NULL); + return PICO_ERR_OTHER; + } else { + this->cbIn = cbIn; + return PICO_OK; + } + +} + +pico_status_t picodata_setCbOut(picodata_ProcessingUnit this, picodata_CharBuffer cbOut) +{ + if (NULL == this) { + picoos_emRaiseException(this->common->em,PICO_ERR_NULLPTR_ACCESS,NULL,NULL); + return PICO_ERR_OTHER; + } else { + this->cbOut = cbOut; + return PICO_OK; + } +} + + +/* *************************************************************** + * auxiliary functions * + *****************************************************************/ + +static void transDurUniform( + picoos_uint8 frame_duration_exp, /* 2's exponent of frame duration in ms, e.g. 2 for 4ms, 3 for 8ms */ + picoos_int8 array_length, + picoos_uint8 * inout, + picoos_int16 inputdur, /* input duration in ms */ + picoos_int16 targetdur, /* target duration in ms */ + picoos_int16 * restdur /* in/out, rest in ms */ + ) +{ + picoos_int8 i; + picoos_int32 fact, rest; + + /* calculate rest and factor in number of frames (in PICODATA_PICODATA_PRECISION) */ + rest = (*restdur) << (PICODATA_PRECISION - frame_duration_exp); + fact = (targetdur << (PICODATA_PRECISION - frame_duration_exp)) / inputdur; + + for (i = 0; i < array_length; i++) { + rest += fact * inout[i]; + /* instead of rounding, we carry the rest to the next state */ + inout[i] = rest >> PICODATA_PRECISION; + rest -= inout[i] << PICODATA_PRECISION; + } + (*restdur) = rest >> (PICODATA_PRECISION - frame_duration_exp); +} + +static void transDurWeighted( + picoos_uint8 frame_duration_exp, /* 2's exponent of frame duration in ms, e.g. 2 for 4ms, 3 for 8ms */ + picoos_int8 array_length, + picoos_uint8 * inout, + const picoos_uint16 * weight, /* integer weights */ + picoos_int16 inputdur, /* input duration in ms */ + picoos_int16 targetdur, /* target duration in ms */ + picoos_int16 * restdur /* in/out, rest in ms */ + ) +{ + picoos_int8 i; + picoos_int32 fact, rest, out, weighted_sum; + + /* calculate rest and factor in number of frames (in PICODATA_PICODATA_PRECISION) */ + rest = (*restdur) << (PICODATA_PRECISION - frame_duration_exp); + weighted_sum = 0; + for (i=0; i < array_length; i++) { + weighted_sum += inout[i] * weight[i]; + } + if (0 == weighted_sum) { + transDurUniform(frame_duration_exp,array_length,inout,inputdur,targetdur,restdur); + return; + } + /* get the additive change factor in PICODATA_PRECISION: */ + if (targetdur > inputdur) { + fact = ((targetdur - inputdur) << (PICODATA_PRECISION-frame_duration_exp))/ weighted_sum; + } else { + fact = -((inputdur - targetdur) << (PICODATA_PRECISION-frame_duration_exp))/ weighted_sum; + } + + /* input[i] * fact * weight[i] is the additive modification in PICODATA_PRECISION */ + for (i=0; i < array_length; i++) { + rest += fact * inout[i] * weight[i]; + /* instead of rounding, we carry the rest to the next state */ + out = inout[i] + (rest >> PICODATA_PRECISION); + if (out < 0) { + out = 0; + } + if (out-inout[i] >= 0) + rest -= ((out-inout[i]) << PICODATA_PRECISION); + else + rest += ((inout[i]-out) << PICODATA_PRECISION); + inout[i] = out; + } + (*restdur) = rest >> (PICODATA_PRECISION - frame_duration_exp); +} + + + +void picodata_transformDurations( + picoos_uint8 frame_duration_exp, + picoos_int8 array_length, + picoos_uint8 * inout, + const picoos_uint16 * weight, /* integer weights */ + picoos_int16 mintarget, /* minimum target duration in ms */ + picoos_int16 maxtarget, /* maximum target duration in ms */ + picoos_int16 facttarget, /* factor to be multiplied with original length to get the target + the factor is fixed-point with PICODATA_PRECISION PICODATA_PRECISION, i.e. + the factor as float would be facttarget / PICODATA_PRECISION_FACT + if factor is 0, only min/max are considered */ + picoos_int16 * dur_rest /* in/out, rest in ms */ + ) +{ + picoos_int32 inputdur, targetdur; + picoos_int8 i; + + /* find the original duration in ms */ + inputdur = 0; + for (i=0; i < array_length; i++) { + inputdur += inout[i]; + } + + PICODBG_TRACE(("######## transforming duration fact=%i, limits = [%i,%i] (input frames: %i)",facttarget,mintarget,maxtarget, inputdur)); + + inputdur <<= frame_duration_exp; + + /* find the target duration */ + if (facttarget) { + targetdur = (facttarget * inputdur + PICODATA_PREC_HALF) >> PICODATA_PRECISION; + } else { + targetdur = inputdur; + } + + /* we need to modify input if there is an explicit factor or input is not in the target range */ + if (facttarget || (targetdur < mintarget) || (maxtarget < targetdur)) { + /* make sure we are in the limits */ + if (targetdur < mintarget) { + targetdur = mintarget; + } else if (maxtarget < targetdur) { + targetdur = maxtarget; + } + /* perform modification */ + if (NULL == weight) { + transDurUniform(frame_duration_exp,array_length,inout,inputdur,targetdur,dur_rest); + } else { + transDurWeighted(frame_duration_exp,array_length,inout,weight,inputdur,targetdur,dur_rest); + } + } +} + + + +extern picoos_uint8 picodata_getPuTypeFromExtension(picoos_uchar * filename, picoos_bool input) +{ + if (input) { + if (picoos_has_extension(filename, PICODATA_PUTYPE_TOK_INPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_TOK; + } + else if (picoos_has_extension(filename, PICODATA_PUTYPE_PR_INPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_PR; + } + else if (picoos_has_extension(filename, PICODATA_PUTYPE_WA_INPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_WA; + } + else if (picoos_has_extension(filename, PICODATA_PUTYPE_SA_INPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_SA; + } + else if (picoos_has_extension(filename, PICODATA_PUTYPE_ACPH_INPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_ACPH; + } + else if (picoos_has_extension(filename, PICODATA_PUTYPE_SPHO_INPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_SPHO; + } + else if (picoos_has_extension(filename, PICODATA_PUTYPE_PAM_INPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_PAM; + } + else if (picoos_has_extension(filename, PICODATA_PUTYPE_CEP_INPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_CEP; + } + else if (picoos_has_extension(filename, PICODATA_PUTYPE_SIG_INPUT_EXTENSION) || + picoos_has_extension(filename, PICODATA_PUTYPE_WAV_INPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_SIG; + } + else { + return PICODATA_ITEMINFO2_CMD_TO_UNKNOWN; + } + } + else { + if (picoos_has_extension(filename, PICODATA_PUTYPE_TOK_OUTPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_TOK; + } + else if (picoos_has_extension(filename, PICODATA_PUTYPE_PR_OUTPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_PR; + } + else if (picoos_has_extension(filename, PICODATA_PUTYPE_WA_OUTPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_WA; + } + else if (picoos_has_extension(filename, PICODATA_PUTYPE_SA_OUTPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_SA; + } + else if (picoos_has_extension(filename, PICODATA_PUTYPE_ACPH_OUTPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_ACPH; + } + else if (picoos_has_extension(filename, PICODATA_PUTYPE_SPHO_OUTPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_SPHO; + } + else if (picoos_has_extension(filename, PICODATA_PUTYPE_PAM_OUTPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_PAM; + } + else if (picoos_has_extension(filename, PICODATA_PUTYPE_CEP_OUTPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_CEP; + } + else if (picoos_has_extension(filename, PICODATA_PUTYPE_SIG_OUTPUT_EXTENSION) || + picoos_has_extension(filename, PICODATA_PUTYPE_WAV_OUTPUT_EXTENSION)) { + return PICODATA_ITEMINFO2_CMD_TO_SIG; + } + else { + return PICODATA_ITEMINFO2_CMD_TO_UNKNOWN; + } + } + return PICODATA_ITEMINFO2_CMD_TO_UNKNOWN; +} + + + + +/** + * + * @param transducer + * @param common + * @param xsampa_parser + * @param svoxpa_parser + * @param xsampa2svoxpa_mapper + * @param inputPhones + * @param alphabet + * @param outputPhoneIds + * @param maxOutputPhoneIds + * @return + */ +pico_status_t picodata_mapPAStrToPAIds(picotrns_SimpleTransducer transducer, + picoos_Common common, picokfst_FST xsampa_parser, + picokfst_FST svoxpa_parser, picokfst_FST xsampa2svoxpa_mapper, + picoos_uchar * inputPhones, picoos_uchar * alphabet, + picoos_uint8 * outputPhoneIds, picoos_int32 maxOutputPhoneIds) +{ + pico_status_t status = PICO_OK; + if (picoos_strcmp(alphabet, PICODATA_XSAMPA) == 0) { + if ((NULL != xsampa_parser) && (NULL != xsampa2svoxpa_mapper)) { + picotrns_stInitialize(transducer); + status = picotrns_stAddWithPlane(transducer, inputPhones, + PICOKFST_PLANE_ASCII); + if (PICO_OK != status) { + picoos_emRaiseWarning(common->em, status, NULL, + (picoos_char *) "phoneme sequence too long (%s)", + inputPhones); + } else { + status = picotrns_stTransduce(transducer, xsampa_parser); + if (PICO_OK != status) { + picoos_emRaiseWarning(common->em, status, NULL, + (picoos_char *) "not recognized as xsampa (%s)", + inputPhones); + } else { + status = picotrns_stTransduce(transducer, xsampa2svoxpa_mapper); + if (PICO_OK != status) { + picoos_emRaiseWarning(common->em, status, NULL, + (picoos_char *) "illeagal phoneme sequence (%s)", + inputPhones); + } else { + status = picotrns_stGetSymSequence(transducer, outputPhoneIds, + maxOutputPhoneIds); + } + } + } + return status; + } + } else if (picoos_strcmp(alphabet, PICODATA_SVOXPA) == 0) { + if ((NULL != svoxpa_parser)) { + picotrns_stInitialize(transducer); + status = picotrns_stAddWithPlane(transducer, inputPhones, + PICOKFST_PLANE_ASCII); + if (PICO_OK == status) { + status = picotrns_stTransduce(transducer, svoxpa_parser); + } + if (PICO_OK == status) { + status = picotrns_stGetSymSequence(transducer, outputPhoneIds, + maxOutputPhoneIds); + } + return status; + } + } + picoos_strlcpy(outputPhoneIds, (picoos_char *) "", maxOutputPhoneIds); + picoos_emRaiseWarning(common->em, PICO_EXC_NAME_ILLEGAL, NULL, + (picoos_char *) "alphabet not supported (%s)", alphabet); + return PICO_EXC_NAME_ILLEGAL; + +} + +#if defined (PICO_DEBUG) +/* *************************************************************** + * For Debugging only * + *****************************************************************/ + + +/* put string representation of 'itemtype' into 'str' (allocated size 'strsize') + * return 'str' */ +static picoos_char * data_itemtype_to_string(const picoos_uint8 itemtype, + picoos_char * str, picoos_uint16 strsize) +{ + picoos_char * tmpstr; + switch (itemtype) { + case PICODATA_ITEM_BOUND: + tmpstr = (picoos_char *)"BOUND"; + break; + case PICODATA_ITEM_FRAME_PAR: + tmpstr = (picoos_char *)"FRAME_PAR"; + break; + case PICODATA_ITEM_PHONE: + tmpstr = (picoos_char *)"PHONE"; + break; + case PICODATA_ITEM_CMD: + tmpstr = (picoos_char *)"CMD"; + break; + case PICODATA_ITEM_ERR: + tmpstr = (picoos_char *)"ERR"; + break; + case PICODATA_ITEM_FRAME: + tmpstr = (picoos_char *)"FRAME"; + break; + case PICODATA_ITEM_OTHER: + tmpstr = (picoos_char *)"OTHER"; + break; + case PICODATA_ITEM_PUNC: + tmpstr = (picoos_char *)"PUNC"; + break; + case PICODATA_ITEM_SYLLPHON: + tmpstr = (picoos_char *)"SYLLPHON"; + break; + case PICODATA_ITEM_WORDGRAPH: + tmpstr = (picoos_char *)"WORDGRAPH"; + break; + case PICODATA_ITEM_WORDINDEX: + tmpstr = (picoos_char *)"WORDINDEX"; + break; + case PICODATA_ITEM_WORDPHON: + tmpstr = (picoos_char *)"WORDPHON"; + break; + case PICODATA_ITEM_WSEQ_GRAPH: + tmpstr = (picoos_char *)"WSEQ_GRAPH"; + break; + default: + tmpstr = (picoos_char *)"UNKNOWN"; + break; + } + picopal_slprintf((picopal_char *) str, strsize, (picopal_char *)"%s", + tmpstr); + return str; +} + + +picoos_char * picodata_head_to_string(const picodata_itemhead_t *head, + picoos_char * str, picoos_uint16 strsize) +{ + picoos_uint16 typelen; + + if (NULL == head) { + picoos_strlcpy(str,(picoos_char *)"[head is NULL]",strsize); + } else { + data_itemtype_to_string(head->type, str, strsize); + typelen = picoos_strlen(str); + picopal_slprintf((picopal_char *) str+typelen, strsize-typelen, + (picopal_char *)"|%c|%c|%i", head->info1, head->info2, + head->len); + } + + return str; +} + +void picodata_info_item(const picoknow_KnowledgeBase kb, + const picoos_uint8 *pref6ch, + const picoos_uint8 *item, + const picoos_uint16 itemlenmax, + const picoos_char *filterfn) +{ +#define SA_USE_PHST 1 + picoos_uint16 i; + picoos_uint8 ch; + + if ((itemlenmax < 4) || (item == NULL)) { + PICODBG_INFO_MSG(("invalid item\n")); + } + + /* first 6 char used for prefix */ + PICODBG_INFO_MSG_F(filterfn, ("%6s(", pref6ch)); + + /* type */ + ch = item[0]; + if ((32 <= ch) && (ch < 127)) { + PICODBG_INFO_MSG_F(filterfn, ("'%c',", ch)); + } else { + PICODBG_INFO_MSG_F(filterfn, ("%3d,", ch)); + } + /* info1 */ + ch = item[1]; + if ((32 <= ch) && (ch < 127)) + switch (item[0]) { + case PICODATA_ITEM_PUNC: + case PICODATA_ITEM_BOUND: + case PICODATA_ITEM_CMD: + case PICODATA_ITEM_TOKEN: + case PICODATA_ITEM_FRAME_PAR: + PICODBG_INFO_MSG_F(filterfn, ("'%c',", ch)); + break; + default: + PICODBG_INFO_MSG_F(filterfn, ("%3d,", ch)); + } + else + PICODBG_INFO_MSG_F(filterfn, ("%3d,", ch)); + + /* info2 */ + ch = item[2]; + if ((32 <= ch) && (ch < 127)) + switch (item[0]) { + case PICODATA_ITEM_PUNC: + case PICODATA_ITEM_BOUND: + case PICODATA_ITEM_CMD: + case PICODATA_ITEM_WORDPHON: + case PICODATA_ITEM_SYLLPHON: + PICODBG_INFO_MSG_F(filterfn, ("'%c',", ch)); + break; + default: + PICODBG_INFO_MSG_F(filterfn, ("%3d,", ch)); + } + else + PICODBG_INFO_MSG_F(filterfn, ("%3d,", ch)); + + /* len */ + ch = item[3]; + PICODBG_INFO_MSG_F(filterfn, ("%3d)", ch)); + + for (i = 0; i < ch; i++) { + if ((item[0] == PICODATA_ITEM_WSEQ_GRAPH) || + (item[0] == PICODATA_ITEM_TOKEN) || + (item[0] == PICODATA_ITEM_WORDGRAPH) || + ((item[0] == PICODATA_ITEM_CMD) && !((item[1] == PICODATA_ITEMINFO1_CMD_SPEED) || + (item[1] == PICODATA_ITEMINFO1_CMD_PITCH) || + (item[1] == PICODATA_ITEMINFO1_CMD_VOLUME) || + (item[1] == PICODATA_ITEMINFO1_CMD_SPELL) || + (item[1] == PICODATA_ITEMINFO1_CMD_SIL)))) { + PICODBG_INFO_MSG_F(filterfn, ("%c", item[4 + i])); + } else { + PICODBG_INFO_MSG_F(filterfn, ("%4d", item[4 + i])); + } + } + +#if defined (SA_USE_PHST) + { +#include "picokdbg.h" + picoos_uint8 j; + picokdbg_Dbg kdbg; + kdbg = picokdbg_getDbg(kb); + + if ((item[0] == PICODATA_ITEM_WORDPHON) || + (item[0] == PICODATA_ITEM_SYLLPHON) || + ((item[0] == PICODATA_ITEM_CMD) && (item[1] == PICODATA_ITEMINFO1_CMD_PHONEME))) { + if (picokdbg_getPhoneSym(kdbg, item[4])) { + PICODBG_INFO_MSG_F(filterfn, (" ")); + for (j = 0; j < item[3]; j++) { + PICODBG_INFO_MSG_F(filterfn, ("%s", + picokdbg_getPhoneSym(kdbg, item[4 + j]))); + } + } + } + } +#endif + + PICODBG_INFO_MSG_F(filterfn, ("\n")); +} + + +#endif /* PICO_DEBUG */ + +#ifdef __cplusplus +} +#endif + + +/* picodata.c end */ diff --git a/pico/lib/picodata.h b/pico/lib/picodata.h new file mode 100644 index 0000000..2105051 --- /dev/null +++ b/pico/lib/picodata.h @@ -0,0 +1,643 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picodata.h + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ +#ifndef PICODATA_H_ +#define PICODATA_H_ + +#include "picodefs.h" +#include "picoos.h" +#include "picotrns.h" +#include "picokfst.h" +#include "picorsrc.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* *************************************************************** + * Constants * + *****************************************************************/ + +#define PICODATA_MAX_ITEMS_PER_PHRASE 30 + +/** + * @addtogroup picodata + * Pico Data : Item Format \n + * + The item header is identical for all item types and PUs. Item types + that are not handled by a PU are copied. + + Item Header structure\n + --------------------- + - Byte Content + - 0x00 item type + - 0x01 item info 1 + - 0x02 item info 2 + - 0x03 item length in bytes (not including the header) + + depending on the item type/info, a specific subheader may follow + (included in length) +*/ + +/* item header fields (tmp.: use item functions below to acces header fields */ +#define PICODATA_ITEMIND_TYPE 0 +#define PICODATA_ITEMIND_INFO1 1 +#define PICODATA_ITEMIND_INFO2 2 +#define PICODATA_ITEMIND_LEN 3 + +/* *************************************************************** + * CharBuffer * + *****************************************************************/ +typedef struct picodata_char_buffer * picodata_CharBuffer; + +picodata_CharBuffer picodata_newCharBuffer(picoos_MemoryManager mm, + picoos_Common common, picoos_objsize_t size); + +void picodata_disposeCharBuffer(picoos_MemoryManager mm, + picodata_CharBuffer * this); + +/* should not be used for PUs but only for feeding the initial cb */ +pico_status_t picodata_cbPutCh(register picodata_CharBuffer this, picoos_char ch); + +/* should not be used for PUs other than first PU in the chain (picotok) */ +picoos_int16 picodata_cbGetCh(register picodata_CharBuffer this); + +/* reset cb (as if after newCharBuffer) */ +pico_status_t picodata_cbReset (register picodata_CharBuffer this); + +/* ** CharBuffer item functions, cf. below in items section ****/ + +/* *************************************************************** + * items * + *****************************************************************/ + +/* item header size */ +#define PICODATA_ITEM_HEADSIZE 4 + +typedef struct picodata_itemhead +{ + picoos_uint8 type; + picoos_uint8 info1; + picoos_uint8 info2; + picoos_uint8 len; +} picodata_itemhead_t; + + +/* -------------- System wide defines referred to by items -------- */ +/* ---- These maybe better stored in a knowledge module/resoruce*/ +#define PICODATA_ACC0 '\x30' /* 48 '0' */ +#define PICODATA_ACC1 '\x31' /* 49 '1' */ +#define PICODATA_ACC2 '\x32' /* 50 '2' */ +#define PICODATA_ACC3 '\x33' /* 51 '3' */ +#define PICODATA_ACC4 '\x34' /* 52 '4' */ + +/* reserved for future use: + * user-imposed Part-Of-Speech ids for user lexica and phoneme tags + * These values should be applied BEFORE POS-disambiguation. The POS lingware either assigns the same + * ids to corresponding internal unique or composed POS or else the POS-D will consider these values + * "default" */ +#define PICODATA_POS_XNPR 20 +#define PICODATA_POS_XN 21 +#define PICODATA_POS_XV 22 +#define PICODATA_POS_XA 23 +#define PICODATA_POS_XADV 24 +#define PICODATA_POS_XX 25 + +/* ------------------------- item types ---------------------------- */ +/* new item types, info1, info2 to be defined during PU development */ +/* make sure this stays in sync with "is_valid_itemtype" function */ +#define PICODATA_ITEM_WSEQ_GRAPH '\x73' /* 115, 's' */ +#define PICODATA_ITEM_TOKEN '\x74' /* 116 't' */ +#define PICODATA_ITEM_WORDGRAPH '\x67' /* 103 'g' */ +#define PICODATA_ITEM_WORDINDEX '\x69' /* 105 'i' */ +#define PICODATA_ITEM_WORDPHON '\x77' /* 119 'w' */ +#define PICODATA_ITEM_SYLLPHON '\x79' /* 121 'y' */ +#define PICODATA_ITEM_BOUND '\x62' /* 98 'b' */ +/* #define PICODATA_ITEM_BOUND_DUR '\x64' */ /* 100 'd' */ /* duration-constrained bound */ +#define PICODATA_ITEM_PUNC '\x70' /* 112 'p' */ +#define PICODATA_ITEM_CMD '\x63' /* 99 'c' */ +#define PICODATA_ITEM_PHONE '\x68' /* 104 'h' */ /*reserved for PAM*/ +#define PICODATA_ITEM_FRAME_PAR '\x6b' /* 107 'k' */ /*reserved for CEP*/ +#define PICODATA_ITEM_FRAME '\x66' /* 102 'f' */ /*reserved for SIG*/ +#define PICODATA_ITEM_OTHER '\x6f' /* 111 'o' */ +#define PICODATA_ITEM_ERR '\x00' /* 0 '^@' */ + +/* generic iteminfo1 */ +#define PICODATA_ITEMINFO1_ERR '\x00' /* 0 '^@' */ /* error state */ +#define PICODATA_ITEMINFO1_NA '\x01' /* 1 '^A' */ /* not applicable */ + +/* generic iteminfo2 */ +#define PICODATA_ITEMINFO2_ERR '\x00' /* 0 '^@' */ /* error state */ +#define PICODATA_ITEMINFO2_NA '\x01' /* 1 '^A' */ /* not applicable */ + +/* ------------------------- PUNC item type ---------------------------- */ +/* iteminfo1 */ +#define PICODATA_ITEMINFO1_PUNC_SENTEND '\x73' /* 115 's' */ +#define PICODATA_ITEMINFO1_PUNC_PHRASEEND '\x70' /* 112 'p' */ +#define PICODATA_ITEMINFO1_PUNC_FLUSH '\x66' /* 102 'f' */ +/* iteminfo2 */ +#define PICODATA_ITEMINFO2_PUNC_SENT_T '\x74' /* 116 't' */ +#define PICODATA_ITEMINFO2_PUNC_SENT_Q '\x71' /* 113 'q' */ +#define PICODATA_ITEMINFO2_PUNC_SENT_E '\x65' /* 101 'e' */ +#define PICODATA_ITEMINFO2_PUNC_PHRASE '\x70' /* 112 'p' */ +#define PICODATA_ITEMINFO2_PUNC_PHRASE_FORCED '\x66' /* 102 'f' */ +/* len for PUNC item is ALWAYS = 0 */ +/* ------------------------- BOUND item type ---------------------------- */ +/* iteminfo1 : phrase strength*/ +#define PICODATA_ITEMINFO1_BOUND_SBEG '\x62' /* 98 'b', at sentence begin */ +#define PICODATA_ITEMINFO1_BOUND_SEND '\x73' /* 115 's', at sentence end */ +#define PICODATA_ITEMINFO1_BOUND_TERM '\x74' /* 116 't', replaces a flush */ +#define PICODATA_ITEMINFO1_BOUND_PHR0 '\x30' /* 48 '0', no break, no item */ +#define PICODATA_ITEMINFO1_BOUND_PHR1 '\x31' /* 49 '1', pri. phrase bound. */ +#define PICODATA_ITEMINFO1_BOUND_PHR2 '\x32' /* 50 '2', short break */ +#define PICODATA_ITEMINFO1_BOUND_PHR3 '\x33' /* 51 '3', sec. phr. bound., no break*/ +/* iteminfo2 : phrase type*/ +#define PICODATA_ITEMINFO2_BOUNDTYPE_P '\x50' /* 80 'P' */ +#define PICODATA_ITEMINFO2_BOUNDTYPE_T '\x54' /* 84 'T' */ +#define PICODATA_ITEMINFO2_BOUNDTYPE_Q '\x51' /* 81 'Q' */ +#define PICODATA_ITEMINFO2_BOUNDTYPE_E '\x45' /* 69 'E' */ +/* len for BOUND item is ALWAYS = 0 */ +/* ------------------------- CMD item type ---------------------------- */ +/* iteminfo1 */ +#define PICODATA_ITEMINFO1_CMD_FLUSH 'f' /* 102 flush command (all PUs)*/ +#define PICODATA_ITEMINFO1_CMD_PLAY 'p' /* 112 play command : PU in info 2 will read items from file-->Filename in item content.*/ +#define PICODATA_ITEMINFO1_CMD_SAVE 's' /* 115 save command : PU in info 2 will save items to file-->Filename in item content.*/ +#define PICODATA_ITEMINFO1_CMD_UNSAVE 'u' /* 117 save command : PU in info 2 will stop saving items to file*/ +#define PICODATA_ITEMINFO1_CMD_PROSDOMAIN 'd' /* 100 prosody domain : domain type in info 2, domain name in item content */ +#define PICODATA_ITEMINFO1_CMD_SPELL 'e' /* 101 spell command : info 2 contains start/stop info, + spell type/pause len as little endian uint16 in item content */ +#define PICODATA_ITEMINFO1_CMD_IGNSIG 'i' /* ignore signal command : info 2 contains start/stop info */ +#define PICODATA_ITEMINFO1_CMD_PHONEME 'o' /* phoneme command : info 2 contains start/stop info, phonemes in item content */ +#define PICODATA_ITEMINFO1_CMD_IGNORE 'I' /* ignore text command : info 2 contains start/stop info */ +#define PICODATA_ITEMINFO1_CMD_SIL 'z' /* silence command : info 2 contains type of silence; + silence duration as little endian uint16 in item content */ +#define PICODATA_ITEMINFO1_CMD_CONTEXT 'c' /* context command : context name in item content */ +#define PICODATA_ITEMINFO1_CMD_VOICE 'v' /* context command : voice name in item content */ +#define PICODATA_ITEMINFO1_CMD_MARKER 'm' /* marker command : marker name in item content */ +#define PICODATA_ITEMINFO1_CMD_PITCH 'P' /* 80 pitch command : abs/rel info in info 2; pitch level as little endian + uint16 in item content; relative value is in promille */ +#define PICODATA_ITEMINFO1_CMD_SPEED 'R' /* 82 speed command : abs/rel info in info 2, speed level as little endian + uint16 in item content; elative value is in promille */ +#define PICODATA_ITEMINFO1_CMD_VOLUME 'V' /* 86 volume command : abs/rel info in info 2, volume level as little endian + uint16 in item content; relative value is in promille */ +#define PICODATA_ITEMINFO1_CMD_SPEAKER 'S' /* 83 speaker command : abs/rel info in info 2, speaker level as little endian + uint16 in item content; relative value is in promille */ + +/* iteminfo2 for PLAY/SAVE */ +#define PICODATA_ITEMINFO2_CMD_TO_TOK 't' /* CMD+PLAY/SAVE+TOKENISATION*/ +#define PICODATA_ITEMINFO2_CMD_TO_PR 'g' /* CMD+PLAY/SAVE+PREPROC*/ +#define PICODATA_ITEMINFO2_CMD_TO_WA 'w' /* CMD+PLAY/SAVE+WORDANA*/ +#define PICODATA_ITEMINFO2_CMD_TO_SA 'a' /* CMD+PLAY/SAVE+SENTANA*/ +#define PICODATA_ITEMINFO2_CMD_TO_ACPH 'h' /* CMD+PLAY/SAVE+ACCENTUATION&PHRASING*/ +#define PICODATA_ITEMINFO2_CMD_TO_SPHO 'p' /* CMD+PLAY/SAVE+ACCENTUATION&PHRASING*/ +#define PICODATA_ITEMINFO2_CMD_TO_PAM 'q' /* CMD+PLAY/SAVE+PHONETIC-ACOUSTIC MAPPING*/ +#define PICODATA_ITEMINFO2_CMD_TO_CEP 'c' /* CMD+PLAY/SAVE+CEP_SMOOTHER*/ +#define PICODATA_ITEMINFO2_CMD_TO_SIG 's' /* CMD+PLAY/SAVE+SIG_GEN */ + +#if 0 +#define PICODATA_ITEMINFO2_CMD_TO_FST 'f' /* CMD+PLAY/SAVE+FST for Syll and Phonotactic constraints*/ +#endif + +#define PICODATA_ITEMINFO2_CMD_TO_UNKNOWN 255 + +/* iteminfo2 for start/end commands */ +#define PICODATA_ITEMINFO2_CMD_START 's' +#define PICODATA_ITEMINFO2_CMD_END 'e' + +/* iteminfo2 for speed/pitch/volume commands */ +#define PICODATA_ITEMINFO2_CMD_ABSOLUTE 'a' +#define PICODATA_ITEMINFO2_CMD_RELATIVE 'r' + +/* len for CMD item could be >= 0 */ +/* ------------------------- TOKEN item type ---------------------------- */ +/* iteminfo1: simple token type : */ +#define PICODATA_ITEMINFO1_TOKTYPE_SPACE 'W' +#define PICODATA_ITEMINFO1_TOKTYPE_LETTERV 'V' +#define PICODATA_ITEMINFO1_TOKTYPE_LETTER 'L' +#define PICODATA_ITEMINFO1_TOKTYPE_DIGIT 'D' +#define PICODATA_ITEMINFO1_TOKTYPE_SEQ 'S' +#define PICODATA_ITEMINFO1_TOKTYPE_CHAR 'C' +#define PICODATA_ITEMINFO1_TOKTYPE_BEGIN 'B' +#define PICODATA_ITEMINFO1_TOKTYPE_END 'E' +#define PICODATA_ITEMINFO1_TOKTYPE_UNDEFINED 'U' +/* iteminfo2 : token subtype */ +/* len for WORDTOK item is ALWAYS > 0, if len==0 an error should be raised */ + +/** + * @addtogroup picodata + * + * ------------------------- WORDGRAPH item type ---------------------------- + * - iteminfo1 : POS and multi-POS values defined in lingware + * - iteminfo2 : not applicable + * - len for WORDGRAPH item is ALWAYS > 0, if len==0 an error should be raised + * (currently picopr may produce empty WORDGRAPH that is eliminated by picowa) + * \n------------------------- WORDINDEX item type ---------------------------- + * - iteminfo1 : POS and multi-POS values defined in lingware + * - iteminfo2 : not applicable + * - len for WORDINDEX item is ALWAYS > 0, if len==0 an error should be raised + * \n------------------------- WORDPHON item type ---------------------------- + * - iteminfo1 : POS values defined in lingware + * - iteminfo2 : Uses PICODATA_ACC0 .. ACC4 + * -len WORDPHON item is ALWAYS > 0, if len==0 an error should be raised + * \n------------------------- SYLLPHON item type ---------------------------- + * - iteminfo1 : not applicable + * - iteminfo2 : Uses PICODATA_ACC0 .. ACC4 + * - len for SYLLPHON item is ALWAYS > 0, if len==0 an error should be raised + * \n------------------------- PHONE item type (PRODUCED BY PAM)----------------- + * - iteminfo1 : phonId : the phonetic identity of the phone + * - iteminfo2 : n_S_P_Phone : number of states per phoneme + * - len for PHON item is ALWAYS > 0, if len==0 an error should be raised + * \n------------------------- FRAME_PAR item type (PRODUCED BY CEP) -------- + * - iteminfo1 : format (float, fixed) + * - iteminfo2 : vector size + * - len for FRAME_PAR item is ALWAYS > 0, if len==0 an error should be raised + * \n------------------------- FRAME item type (PRODUCED BY SIG) ----------- + * - iteminfo1 : number of samples per frame + * - iteminfo2 : number of bytes per sample + * - len for FRAME item is ALWAYS > 0, if len==0 an error should be raised + * + */ +#define PICODATA_ITEMINFO1_FRAME_PAR_DATA_FORMAT_FIXED '\x78' /* 120 'x' fixed point */ +#define PICODATA_ITEMINFO1_FRAME_PAR_DATA_FORMAT_FLOAT '\x66' /* 102 'f' floating point */ + +/* *************************************************************** + * items: CharBuffer functions * + *****************************************************************/ + +/* gets a single item (head and content) from a CharBuffer in buf; + blenmax is the max length (in number of bytes) of buf; blen is + set to the number of bytes gotten in buf; return values: + PICO_OK <- one item gotten + PICO_EOF <- no item available, cb is empty + PICO_EXC_BUF_UNDERFLOW <- cb not empty, but no valid item + PICO_EXC_BUF_OVERFLOW <- buf not large enough +*/ +pico_status_t picodata_cbGetItem(register picodata_CharBuffer this, + picoos_uint8 *buf, const picoos_uint16 blenmax, + picoos_uint16 *blen); + +/* gets the speech data (without item head) from a CharBuffer in buf; + blenmax is the max length (in number of bytes) of buf; blen is + set to the number of bytes gotten in buf; return values: + PICO_OK <- speech data of one item gotten + PICO_EOF <- no item available, cb is empty + PICO_EXC_BUF_UNDERFLOW <- cb not empty, but no valid item + PICO_EXC_BUF_OVERFLOW <- buf not large enough +*/ +pico_status_t picodata_cbGetSpeechData(register picodata_CharBuffer this, + picoos_uint8 *buf, const picoos_uint16 blenmax, + picoos_uint16 *blen); + +/* puts a single item (head and content) to a CharBuffer; clenmax is + the max length (in number of bytes) accessible in content; clen is + set to the number of bytes put from content; return values: + PICO_OK <- one item put + PICO_EXC_BUF_UNDERFLOW <- no valid item in buf + PICO_EXC_BUF_OVERFLOW <- cb not large enough +*/ +pico_status_t picodata_cbPutItem(register picodata_CharBuffer this, + const picoos_uint8 *buf, const picoos_uint16 blenmax, + picoos_uint16 *blen); + +/* unsafe, just for measuring purposes */ +picoos_uint8 picodata_cbGetFrontItemType(register picodata_CharBuffer this); + +/* *************************************************************** + * items: support function * + *****************************************************************/ + +/* checks, whether item of type 'ch' is a valid item type */ +picoos_uint8 is_valid_itemtype(const picoos_uint8 ch); + +/* gets from buf a single item, values in head set and item content + copied to content; blenmax and clenmax are the max lengths (in + number of bytes) accessible in buf and content; clen is set to the + number of bytes gotten in content; return values: + PICO_OK <- all ok + PICO_EXC_BUF_UNDERFLOW <- blenmax problem, or no valid item + PICO_EXC_BUF_OVERFLOW <- overflow in content +*/ +pico_status_t picodata_get_itemparts_nowarn( + const picoos_uint8 *buf, const picoos_uint16 blenmax, + picodata_itemhead_t *head, picoos_uint8 *content, + const picoos_uint16 clenmax, picoos_uint16 *clen); + +/* gets from buf a single item, values in head set and item content + copied to content; blenmax and clenmax are the max lengths (in + number of bytes) accessible in buf and content; clen is set to the + number of bytes gotten in content; return values: + PICO_OK <- all ok + PICO_EXC_BUF_UNDERFLOW <- blenmax problem, or no valid item + PICO_EXC_BUF_OVERFLOW <- overflow in content +*/ +pico_status_t picodata_get_itemparts( + const picoos_uint8 *buf, const picoos_uint16 blenmax, + picodata_itemhead_t *head, picoos_uint8 *content, + const picoos_uint16 clenmax, picoos_uint16 *clen); + +/* puts a single item to buf; values in head and content copied to + buf; clenmax is the max length (in number of bytes) accessible in + content; blenmax is the max length (bytes) accessible in buf; blen + is set to the number of bytes put to buf; return values: + PICO_OK <- all ok + PICO_EXC_BUF_UNDERFLOW <- clenmax problem, or no valid item + PICO_EXC_BUF_OVERFLOW <- overflow in buf +*/ +pico_status_t picodata_put_itemparts(const picodata_itemhead_t *head, + const picoos_uint8 *content, const picoos_uint16 clenmax, + picoos_uint8 *buf, const picoos_uint16 blenmax, picoos_uint16 *blen); + +/* gets from buf info of a single item, values in head are set and + content is set to the start of content in buf (not copied!); + content is set to NULL if the content length is 0; blenmax is the + max lengths (in number of bytes) accessible in buf; return values: + PICO_OK <- all ok + PICO_EXC_BUF_UNDERFLOW <- blenmax problem, or no valid item +*/ +pico_status_t picodata_get_iteminfo( + picoos_uint8 *buf, const picoos_uint16 blenmax, + picodata_itemhead_t *head, picoos_uint8 **content); + +/* copies the item in inbuf to outbuf after first checking if there is + a valid item in inbuf; inlenmax and outlenmax are the max length + (in number of byte) accessible in the buffers); in *numb the total + number of bytes copied to outbuf (incl. header) is returned; return + values: + PICO_OK <- item copied + PICO_EXC_BUF_OVERFLOW <- overflow in outbuf + PICO_ERR_OTHER <- no valid item in inbuf +*/ +pico_status_t picodata_copy_item(const picoos_uint8 *inbuf, + const picoos_uint16 inlenmax, picoos_uint8 *outbuf, + const picoos_uint16 outlenmax, picoos_uint16 *numb); + +/* sets the info1 field in the header contained in the item in buf; + return values: + PICO_OK <- all ok + PICO_EXC_BUF_UNDERFLOW <- underflow in buf +*/ +pico_status_t picodata_set_iteminfo1(picoos_uint8 *buf, + const picoos_uint16 blenmax, const picoos_uint8 info); + +/* sets the info2 field in the header contained in the item in buf; + return values: + PICO_OK <- all ok + PICO_EXC_BUF_UNDERFLOW <- underflow in buf +*/ +pico_status_t picodata_set_iteminfo2(picoos_uint8 *buf, + const picoos_uint16 blenmax, const picoos_uint8 info); + +/* sets the len field in the header contained in the item in buf; + return values: + PICO_OK <- all ok + PICO_EXC_BUF_UNDERFLOW <- underflow in buf +*/ +pico_status_t picodata_set_itemlen(picoos_uint8 *buf, + const picoos_uint16 blenmax, const picoos_uint8 len); + +/* check item validity and return TRUE if valid; return FALSE if + invalid; ilenmax is the max index to be used in item +*/ +picoos_uint8 picodata_is_valid_item(const picoos_uint8 *item, + const picoos_uint16 ilenmax); + +/* return TRUE if head is a valid item head, FALSE otherwise */ +picoos_uint8 picodata_is_valid_itemhead(const picodata_itemhead_t *head); + + +/* *************************************************************** + * ProcessingUnit * + *****************************************************************/ +/* public */ + +#define PICODATA_MAX_ITEMSIZE (picoos_uint16) (PICODATA_ITEM_HEADSIZE + 256) + +/* different buffer sizes per processing unit */ +#define PICODATA_BUFSIZE_DEFAULT (picoos_uint16) PICODATA_MAX_ITEMSIZE +#define PICODATA_BUFSIZE_TEXT (picoos_uint16) 1 * PICODATA_BUFSIZE_DEFAULT +#define PICODATA_BUFSIZE_TOK (picoos_uint16) 2 * PICODATA_BUFSIZE_DEFAULT +#define PICODATA_BUFSIZE_PR (picoos_uint16) 2 * PICODATA_BUFSIZE_DEFAULT +#define PICODATA_BUFSIZE_WA (picoos_uint16) 2 * PICODATA_BUFSIZE_DEFAULT +#define PICODATA_BUFSIZE_SA (picoos_uint16) 2 * PICODATA_BUFSIZE_DEFAULT +#define PICODATA_BUFSIZE_ACPH (picoos_uint16) 2 * PICODATA_BUFSIZE_DEFAULT +#define PICODATA_BUFSIZE_SPHO (picoos_uint16) 4 * PICODATA_BUFSIZE_DEFAULT +#define PICODATA_BUFSIZE_PAM (picoos_uint16) 4 * PICODATA_BUFSIZE_DEFAULT +#define PICODATA_BUFSIZE_CEP (picoos_uint16) 16 * PICODATA_BUFSIZE_DEFAULT +#define PICODATA_BUFSIZE_SIG (picoos_uint16) 16 * PICODATA_BUFSIZE_DEFAULT +#define PICODATA_BUFSIZE_SINK (picoos_uint16) 1 * PICODATA_BUFSIZE_DEFAULT + +/* different types of processing units */ +typedef enum picodata_putype { + PICODATA_PUTYPE_TEXT, /* text */ + PICODATA_PUTYPE_TOK, /* tokenizer output */ + PICODATA_PUTYPE_PR, /* preprocessor output */ + PICODATA_PUTYPE_WA, /* word analysis */ + PICODATA_PUTYPE_SA, /* sentence analysis */ + PICODATA_PUTYPE_ACPH, /* accentuation and phrasing */ + PICODATA_PUTYPE_SPHO, /* sentence phonology (textana postproc) */ + PICODATA_PUTYPE_PAM, /* phonetics to acoustics mapper processing unit */ + PICODATA_PUTYPE_CEP, /* cepstral smoothing processing unit */ + PICODATA_PUTYPE_SIG, /* signal generation processing unit*/ + PICODATA_PUTYPE_SINK /* item sink unit*/ +} picodata_putype_t; + +picoos_uint16 picodata_get_default_buf_size (picodata_putype_t puType); + +/* result values returned from the pu->puStep() methode */ +typedef enum picodata_step_result { + PICODATA_PU_ERROR, + /* PICODATA_PU_EMPTY, *//* reserved (no internal data to be processed) */ + PICODATA_PU_IDLE, /* need more input to process internal data */ + PICODATA_PU_BUSY, /* processing internal data */ + PICODATA_PU_ATOMIC, /* same as pu_busy, but wants to get next time slot (while in an "atomar" operation) */ + PICODATA_PU_OUT_FULL /* can't proceed because output is full. (next time slot to be assigned to pu's output's consumer) */ +} picodata_step_result_t; + +typedef struct picodata_processing_unit * picodata_ProcessingUnit; + +picodata_ProcessingUnit picodata_newProcessingUnit( + picoos_MemoryManager mm, + picoos_Common common, + picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, + picorsrc_Voice voice); + +void picodata_disposeProcessingUnit( + picoos_MemoryManager mm, + picodata_ProcessingUnit * this); + +picodata_CharBuffer picodata_getCbIn(picodata_ProcessingUnit this); +picodata_CharBuffer picodata_getCbOut(picodata_ProcessingUnit this); +pico_status_t picodata_setCbIn(picodata_ProcessingUnit this, picodata_CharBuffer cbIn); +pico_status_t picodata_setCbOut(picodata_ProcessingUnit this, picodata_CharBuffer cbOut); + +/* protected */ +typedef pico_status_t (* picodata_puInitializeMethod) (register picodata_ProcessingUnit this, picoos_int32 mode); +typedef pico_status_t (* picodata_puTerminateMethod) (register picodata_ProcessingUnit this); +typedef picodata_step_result_t (* picodata_puStepMethod) (register picodata_ProcessingUnit this, picoos_int16 mode, picoos_uint16 * numBytesOutput); +typedef pico_status_t (* picodata_puSubDeallocateMethod) (register picodata_ProcessingUnit this, picoos_MemoryManager mm); + +typedef struct picodata_processing_unit +{ + /* public */ + picodata_puInitializeMethod initialize; + picodata_puStepMethod step; + picodata_puTerminateMethod terminate; + picorsrc_Voice voice; + + /* protected */ + picoos_Common common; + picodata_CharBuffer cbIn, cbOut; + picodata_puSubDeallocateMethod subDeallocate; + void * subObj; + +} picodata_processing_unit_t; + +/* currently, only wav input and output is supported */ +#define PICODATA_PUTYPE_TEXT_OUTPUT_EXTENSION (picoos_uchar*)".txt" +#define PICODATA_PUTYPE_TOK_INPUT_EXTENSION PICODATA_PUTYPE_TEXT_OUTPUT_EXTENSION +#define PICODATA_PUTYPE_TOK_OUTPUT_EXTENSION (picoos_uchar*)".tok" +#define PICODATA_PUTYPE_PR_INPUT_EXTENSION PICODATA_PUTYPE_TOK_OUTPUT_EXTENSION +#define PICODATA_PUTYPE_PR_OUTPUT_EXTENSION (picoos_uchar*)".pr" +#define PICODATA_PUTYPE_WA_INPUT_EXTENSION PICODATA_PUTYPE_PR_OUTPUT_EXTENSION +#define PICODATA_PUTYPE_WA_OUTPUT_EXTENSION (picoos_uchar*)".wa" +#define PICODATA_PUTYPE_SA_INPUT_EXTENSION PICODATA_PUTYPE_WA_OUTPUT_EXTENSION +#define PICODATA_PUTYPE_SA_OUTPUT_EXTENSION (picoos_uchar*)".sa" +#define PICODATA_PUTYPE_ACPH_INPUT_EXTENSION PICODATA_PUTYPE_SA_OUTPUT_EXTENSION +#define PICODATA_PUTYPE_ACPH_OUTPUT_EXTENSION (picoos_uchar*)".acph" +#define PICODATA_PUTYPE_SPHO_INPUT_EXTENSION PICODATA_PUTYPE_ACPH_OUTPUT_EXTENSION +#define PICODATA_PUTYPE_SPHO_OUTPUT_EXTENSION (picoos_uchar*)".spho" +#define PICODATA_PUTYPE_PAM_INPUT_EXTENSION PICODATA_PUTYPE_SPHO_OUTPUT_EXTENSION +#define PICODATA_PUTYPE_PAM_OUTPUT_EXTENSION (picoos_uchar*)".pam" +#define PICODATA_PUTYPE_CEP_INPUT_EXTENSION PICODATA_PUTYPE_PAM_OUTPUT_EXTENSION +#define PICODATA_PUTYPE_CEP_OUTPUT_EXTENSION (picoos_uchar*)".cep" +#define PICODATA_PUTYPE_SIG_INPUT_EXTENSION PICODATA_PUTYPE_CEP_OUTPUT_EXTENSION /*PP 11.7.08*/ +#define PICODATA_PUTYPE_SIG_OUTPUT_EXTENSION (picoos_uchar*)".sig" +#define PICODATA_PUTYPE_SINK_INPUT_EXTENSION PICODATA_PUTYPE_SIG_OUTPUT_EXTENSION + +/*wav input is for play wav files in sig */ +#define PICODATA_PUTYPE_WAV_INPUT_EXTENSION (picoos_uchar*)".wav" /*PP 11.7.08*/ + +/*wav output is for saving wav (binary) files in sig*/ +#define PICODATA_PUTYPE_WAV_OUTPUT_EXTENSION (picoos_uchar*)".wav" /*PP 14.7.08*/ + +/* *************************************************************** + * auxiliary routines * + *****************************************************************/ + +picoos_uint8 picodata_getPuTypeFromExtension(picoos_uchar * filename, picoos_bool input); + +#define PICODATA_XSAMPA (picoos_uchar *)"xsampa" +#define PICODATA_SAMPA (picoos_uchar *)"sampa" +#define PICODATA_SVOXPA (picoos_uchar *)"svoxpa" + +/*----------------------------------------------------------*/ +/** @brief maps an input phone string to its internal representation + * + * @param transducer initialized SimpleTransducer + * @param xsampa_parser fst converting xsampa char input to xsampa ids + * @param svoxpa_parser + * @param xsampa2svoxpa_mapper + * @param inputPhones input phone string in alphabet 'alphabet' + * @param alphabet input alphabet + * @retval outputPhoneIds output phone string in internal representation + * @param maxOutputPhoneIds + * @return PICO_OK=mapping done, PICO_ERR_OTHER:unknown alphabet, unknown phones + */ +/*---------------------------------------------------------*/ +pico_status_t picodata_mapPAStrToPAIds( + picotrns_SimpleTransducer transducer, + picoos_Common common, + picokfst_FST xsampa_parser, + picokfst_FST svoxpa_parser, + picokfst_FST xsampa2svoxpa_mapper, + picoos_uchar * inputPhones, + picoos_uchar * alphabet, + picoos_uint8 * outputPhoneIds, + picoos_int32 maxOutputPhoneIds); + +/* number of binary digits after the comma for fixed-point calculation */ +#define PICODATA_PRECISION 10 +/* constant 0.5 in PICODATA_PRECISION */ +#define PICODATA_PREC_HALF 512 + +void picodata_transformDurations( + picoos_uint8 frame_duration_exp, + picoos_int8 array_length, + picoos_uint8 * inout, + const picoos_uint16 * weight, /* integer weights */ + picoos_int16 mintarget, /* minimum target duration in ms */ + picoos_int16 maxtarget, /* maximum target duration in ms */ + picoos_int16 facttarget, /* factor to be multiplied with original length to get the target + the factor is fixed-point with precision PRECISION, i.e. + the factor as float would be facttarget / PRECISION_FACT + if factor is 0, only min/max are considered */ + picoos_int16 * dur_rest /* in/out, rest in ms */ + ); + + + +/* *************************************************************** + * For Debugging only * + *****************************************************************/ + +#if defined (PICO_DEBUG) + +/* convert (pretty print) item head 'head' and put output in 'str', + strsize is the maximum length of 'str' in bytes */ +picoos_char * picodata_head_to_string(const picodata_itemhead_t *head, + picoos_char * str, picoos_uint16 strsize); + +/* put 'pref6ch' (max. 6 char prefix) and a pretty print output of + 'item' in 'str', strlenmax is the maximum length of 'str' in + bytes */ +void picodata_info_item(const picoknow_KnowledgeBase kb, + const picoos_uint8 *pref6ch, + const picoos_uint8 *item, + const picoos_uint16 itemlenmax, + const picoos_char *filterfn); + + +#define PICODATA_INFO_ITEM(kb, pref, item, itemlenmax) \ + PICODBG_INFO_CTX(); \ + picodata_info_item(kb, pref, item, itemlenmax, (picoos_char *)__FILE__) + + + +#else + +#define PICODATA_INFO_ITEM(kb, pref, item, itemlenmax) + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /*PICODATA_H_*/ diff --git a/pico/lib/picodbg.c b/pico/lib/picodbg.c new file mode 100644 index 0000000..8fa753b --- /dev/null +++ b/pico/lib/picodbg.c @@ -0,0 +1,438 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picodbg.c + * + * Provides functions and macros to debug the Pico system and to trace + * the execution of its code. + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + */ + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +#if defined(PICO_DEBUG) + +/* Two variants of colored console output are implemented: + COLOR_MODE_WINDOWS + uses the Windows API function SetConsoleTextAttribute + COLOR_MODE_ANSI + uses ANSI escape codes */ +#if defined(_WIN32) +#define COLOR_MODE_WINDOWS +#else +#define COLOR_MODE_ANSI +#endif + + +#include +#include + +#include +#include + +#include "picodbg.h" + + +/* Maximum length of a formatted tracing message */ +#define MAX_MESSAGE_LEN 999 + +/* Maximum length of contextual information */ +#define MAX_CONTEXT_LEN 499 + +/* Maximum length of filename filter */ +#define MAX_FILTERFN_LEN 16 + +/* Delimiter used in debug messages */ +#define MSG_DELIM "|" + +/* Standard output file for debug messages */ +#define STDDBG stdout /* or stderr */ + +/* Default setup */ +#define PICODBG_DEFAULT_LEVEL PICODBG_LOG_LEVEL_WARN +#define PICODBG_DEFAULT_FILTERFN "" +#define PICODBG_DEFAULT_FORMAT \ + (PICODBG_SHOW_LEVEL | PICODBG_SHOW_SRCNAME | PICODBG_SHOW_FUNCTION) +#define PICODBG_DEFAULT_COLOR 1 + + +/* Current log level */ +static int logLevel = PICODBG_DEFAULT_LEVEL; + +/* Current log filter (filename) */ +static char logFilterFN[MAX_FILTERFN_LEN + 1]; + +/* Current log file or NULL if no log file is set */ +static FILE *logFile = NULL; + +/* Current output format */ +static int logFormat = PICODBG_DEFAULT_FORMAT; + +/* Color mode for console output (0 : disable colors, != 0 : enable colors */ +static int optColor = 0; + +/* Buffer for context information */ +static char ctxbuf[MAX_CONTEXT_LEN + 1]; + +/* Buffer to format tracing messages */ +static char msgbuf[MAX_MESSAGE_LEN + 1]; + + +/* *** Support for colored text output to console *****/ + + +/* Console text colors */ +enum color_t { + /* order matches Windows color codes */ + ColorBlack, + ColorBlue, + ColorGreen, + ColorCyan, + ColorRed, + ColorPurple, + ColorBrown, + ColorLightGray, + ColorDarkGray, + ColorLightBlue, + ColorLightGreen, + ColorLightCyan, + ColorLightRed, + ColorLightPurple, + ColorYellow, + ColorWhite +}; + + +static enum color_t picodbg_getLevelColor(int level) +{ + switch (level) { + case PICODBG_LOG_LEVEL_ERROR: return ColorLightRed; + case PICODBG_LOG_LEVEL_WARN : return ColorYellow; + case PICODBG_LOG_LEVEL_INFO : return ColorGreen; + case PICODBG_LOG_LEVEL_DEBUG: return ColorLightGray; + case PICODBG_LOG_LEVEL_TRACE: return ColorDarkGray; + } + return ColorWhite; +} + + +#if defined(COLOR_MODE_WINDOWS) + +#define WIN32_LEAN_AND_MEAN +#include + +static int picodbg_setTextAttr(FILE *stream, int attr) +{ + HANDLE hConsole; + + if (stream == stdout) { + hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + } else if (stream == stderr) { + hConsole = GetStdHandle(STD_ERROR_HANDLE); + } else { + hConsole = INVALID_HANDLE_VALUE; + } + + if (hConsole != INVALID_HANDLE_VALUE) { + /* do nothing if console output is redirected to a file */ + if (GetFileType(hConsole) == FILE_TYPE_CHAR) { + CONSOLE_SCREEN_BUFFER_INFO csbi; + GetConsoleScreenBufferInfo(hConsole, &csbi); + SetConsoleTextAttribute(hConsole, (WORD) attr); + return (int) csbi.wAttributes; + } + } + + return 0; +} + +#elif defined(COLOR_MODE_ANSI) + +static int picodbg_setTextAttr(FILE *stream, int attr) +{ + const char *c = ""; + + if (attr == -1) { + c = "0"; + } else switch (attr) { + case ColorBlack: c = "0;30"; break; + case ColorRed: c = "0;31"; break; + case ColorGreen: c = "0;32"; break; + case ColorBrown: c = "0;33"; break; + case ColorBlue: c = "0;34"; break; + case ColorPurple: c = "0;35"; break; + case ColorCyan: c = "0;36"; break; + case ColorLightGray: c = "0;37"; break; + case ColorDarkGray: c = "1;30"; break; + case ColorLightRed: c = "1;31"; break; + case ColorLightGreen: c = "1;32"; break; + case ColorYellow: c = "1;33"; break; + case ColorLightBlue: c = "1;34"; break; + case ColorLightPurple: c = "1;35"; break; + case ColorLightCyan: c = "1;36"; break; + case ColorWhite: c = "1;37"; break; + } + + fprintf(stream, "\x1b[%sm", c); + return -1; +} + +#else + +static int picodbg_setTextAttr(FILE *stream, int attr) +{ + /* avoid 'unreferenced formal parameter' */ + (void) stream; + (void) attr; + return 0; +} + +#endif + + +/* *** Auxiliary routines *****/ + + +static const char *picodbg_fileTitle(const char *file) +{ + const char *name = file, *str = file; + + /* try to extract file name without path in a platform independent + way, i.e., skip all chars preceding path separator chars like + '/' (Unix, MacOSX), '\' (Windows, DOS), and ':' (MacOS9) */ + while (*str) { + if ((*str == '\\') || (*str == '/') || (*str == ':')) { + name = str + 1; + } + str++; + } + + return name; +} + + +static void picodbg_logToStream(int level, int donewline, + const char *context, const char *msg) +{ + int oldAttr = 0; + + if (optColor) { + oldAttr = picodbg_setTextAttr(STDDBG, picodbg_getLevelColor(level)); + } + + fprintf(STDDBG, "%s%s", context, msg); + if (donewline) fprintf(STDDBG, "\n"); + if (logFile != NULL) { + fprintf(logFile, "%s%s", context, msg); + if (donewline) fprintf(logFile, "\n"); + } + + if (optColor) { + picodbg_setTextAttr(STDDBG, oldAttr); + } +} + + +/* *** Exported routines *****/ + + +void picodbg_initialize(int level) +{ + logLevel = level; + strcpy(logFilterFN, PICODBG_DEFAULT_FILTERFN); + logFile = NULL; + logFormat = PICODBG_DEFAULT_FORMAT; + optColor = PICODBG_DEFAULT_COLOR; + PICODBG_ASSERT_RANGE(level, 0, PICODBG_LOG_LEVEL_TRACE); +} + + +void picodbg_terminate() +{ + if (logFile != NULL) { + fclose(logFile); + } + + logLevel = 0; + logFile = NULL; +} + + +void picodbg_setLogLevel(int level) +{ + PICODBG_ASSERT_RANGE(level, 0, PICODBG_LOG_LEVEL_TRACE); + logLevel = level; +} + + +void picodbg_setLogFilterFN(const char *name) +{ + strcpy(logFilterFN, name); +} + + +void picodbg_setLogFile(const char *name) +{ + if (logFile != NULL) { + fclose(logFile); + } + + if ((name != NULL) && (strlen(name) > 0)) { + logFile = fopen(name, "wt"); + } else { + logFile = NULL; + } +} + + +void picodbg_enableColors(int flag) +{ + optColor = (flag != 0); +} + + +void picodbg_setOutputFormat(unsigned int format) +{ + logFormat = format; +} + + +const char *picodbg_varargs(const char *format, ...) +{ + int len; + + va_list argptr; + va_start(argptr, format); + + len = vsprintf(msgbuf, format, argptr); + PICODBG_ASSERT_RANGE(len, 0, MAX_MESSAGE_LEN); + + return msgbuf; +} + + +void picodbg_log(int level, int donewline, const char *file, int line, + const char *func, const char *msg) +{ + char cb[MAX_CONTEXT_LEN + 1]; + + PICODBG_ASSERT_RANGE(level, 0, PICODBG_LOG_LEVEL_TRACE); + + if ((level <= logLevel) && + ((strlen(logFilterFN) == 0) || !strcmp(logFilterFN, picodbg_fileTitle(file)))) { + /* compose output format string */ + strcpy(ctxbuf, "*** "); + if (logFormat & PICODBG_SHOW_LEVEL) { + switch (level) { + case PICODBG_LOG_LEVEL_ERROR: + strcat(ctxbuf, "error" MSG_DELIM); + break; + case PICODBG_LOG_LEVEL_WARN: + strcat(ctxbuf, "warn " MSG_DELIM); + break; + case PICODBG_LOG_LEVEL_INFO: + strcat(ctxbuf, "info " MSG_DELIM); + break; + case PICODBG_LOG_LEVEL_DEBUG: + strcat(ctxbuf, "debug" MSG_DELIM); + break; + case PICODBG_LOG_LEVEL_TRACE: + strcat(ctxbuf, "trace" MSG_DELIM); + break; + default: + break; + } + } + if (logFormat & PICODBG_SHOW_DATE) { + /* nyi */ + } + if (logFormat & PICODBG_SHOW_TIME) { + /* nyi */ + } + if (logFormat & PICODBG_SHOW_SRCNAME) { + sprintf(cb, "%-10s", picodbg_fileTitle(file)); + strcat(ctxbuf, cb); + if (logFormat & PICODBG_SHOW_SRCLINE) { + sprintf(cb, "(%d)", line); + strcat(ctxbuf, cb); + } + strcat(ctxbuf, MSG_DELIM); + } + if (logFormat & PICODBG_SHOW_FUNCTION) { + if (strlen(func) > 0) { + sprintf(cb, "%-18s", func); + strcat(ctxbuf, cb); + strcat(ctxbuf, MSG_DELIM); + } + } + + picodbg_logToStream(level, donewline, ctxbuf, msg); + } +} + + +void picodbg_log_msg(int level, const char *file, const char *msg) +{ + PICODBG_ASSERT_RANGE(level, 0, PICODBG_LOG_LEVEL_TRACE); + + if ((level <= logLevel) && + ((strlen(logFilterFN) == 0) || !strcmp(logFilterFN, picodbg_fileTitle(file)))) { + picodbg_logToStream(level, 0, "", msg); + } +} + + +void picodbg_assert(const char *file, int line, const char *func, const char *expr) +{ + if (strlen(func) > 0) { + fprintf(STDDBG, "assertion failed: %s, file %s, function %s, line %d", + expr, picodbg_fileTitle(file), func, line); + } else { + fprintf(STDDBG, "assertion failed: %s, file %s, line %d", + expr, picodbg_fileTitle(file), line); + } + picodbg_terminate(); + abort(); +} + + +#else + +/* To prevent warning about "translation unit is empty" when + diagnostic output is disabled. */ +static void picodbg_dummy(void) { + picodbg_dummy(); +} + +#endif /* defined(PICO_DEBUG) */ + +#ifdef __cplusplus +} +#endif + + +/* end */ diff --git a/pico/lib/picodbg.h b/pico/lib/picodbg.h new file mode 100644 index 0000000..490d3b5 --- /dev/null +++ b/pico/lib/picodbg.h @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * + * @file picodbg.h + * + * Provides functions and macros to debug the Pico system and to trace + * the execution of its code. + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + */ + +/** + * @addtogroup picodbg + * ---------------------------------------------------\n + * Pico Debug Support \n + * ---------------------------------------------------\n + * GENERAL REMARKS + * --------------- + * This module provides a set of macros to help debug the Pico system. + * The usage of macros allows for completely removing debug code from + * the binaries delivered to customers. To enable diagnostic output + * the preprocessor symbol PICO_DEBUG has to be defined. + * + * By using global variables (to store the current log level etc.) + * this module violates a basic Pico design principle! + * + * Justification:\n + * - going without global data would reduce the functionality + * of this module considerably (e.g., log level could not be + * changed at runtime etc.) + * - at the moment, the only known system interdicting global + * variables is Symbian; but even there global variables are + * possible by using thread-local storage + * - allocating global data on the heap would require to pass + * a handle to this memory block to all routines of this + * module which in turn implies that _every_ function in the + * Pico system would require a pointer to some global data; + * obviously, this would be very awkward + * + * Furthermore, this module uses the non-standardized but handy + * __FUNCTION__ macro. It expands to the name of the enclosing + * function. For compilers not supporting this macro simply + * define __FUNCTION__ as an empty string. + * + * + * INITIALIZATION/TERMINATION\n + * --------------------------\n + * Before using any debug macros, this module has to be initialized + * by calling PICODBG_INITIALIZE(). If the routines are not needed + * anymore, PICODBG_TERMINATE() has to be called to terminate the + * module (e.g., to close the log file). + * + * + * TRACING\n + * -------\n + * Each tracing message is associated with a log level which describes + * its severity. The following levels are supported: + * - Trace - Very detailed log messages, potentially of a high + * frequency and volume + * - Debug - Less detailed and/or less frequent debugging messages + * - Info - Informational messages + * - Warn - Warnings which don't appear to the Pico user + * - Error - Error messages + * + * Tracing messages can use the well-known printf format specification. + * But because variadic macros (macros with a variable no. arguments) + * are not commonly supported by compilers a little trick is used + * which requires the format string and its arguments to be enclosed + * in double parenthesis: + * + * - PICODBG_INFO(("hello, world!")); + * - PICODBG_TRACE(("argc=%d", argc)); + * ... + * + * Each tracing message is expected to be a single line of text. Some + * contextual information (e.g., log level, time and date, source file + * and line number) and a newline are automatically added. The output + * format can be customized by a call to PICODBG_SET_OUTPUT_FORMAT(). + * + * Sample output: + * - *** info|2008-04-03|14:51:36|dbgdemo.c(15)|hello world + * - *** trace|2008-04-03|14:51:36|dbgdemo.c(16)|argc=2 + * - ... + * + * To compose a tracing message line consisting of, e.g. the elements + * of an array, on the Info level two additional macros shown in the + * following example are provided: + * + * PICODBG_INFO_CTX();\n + * for (i = 0; i < len; i++)\n + * ...some calc with arr and i\n + * PICODBG_INFO_MSG((" %d", arr[i]));\n + * }\n + * PICODBG_INFO_MSG(("\n"));\n + * + * Colored output of tracing messages helps to capture severe problems + * quickly. This feature is supported on the Windows platform and on + * platforms supporting ANSI escape codes. PICODBG_ENABLE_COLORS() lets + * you turn on and off colored output. + * + * + * FILTERING\n + * ---------\n + * By calling PICODBG_SET_LOG_LEVEL() the log level may be changed at + * any time to increase/decrease the amount of debugging output. + * + * By calling PICODBG_SET_LOG_FILTERFN() the log filter may be changed + * at any time to change the source file name being used as filter for + * log messages (ie. only tracing info of the specified file will be + * logged). To disable the file name based filter set the filter file + * name to an empty string. + * + * Future version of this module might provide further filtering + * possibilities (e.g., filtering based on function names * etc.). + * + * + * LOGGING\n + * -------\n + * By default, tracing messages are output to the console (stderr). + * This allows for separating diagnostic output from other console + * output to stdout. In addition, tracing messages may be saved to + * a file by calling PICODBG_SET_LOG_FILE(). + * Currently, file output is the only additional output target; but + * on embedded systems, more output targets may be required (e.g., + * sending output to a serial port or over the network). + * + * + * ASSERTIONS\n + * ----------\n + * To support the 'design/programming by contract' paradigm, this + * module also provides assertions. PICODBG_ASSERT(expr) evualuates + * an expression and, when the result is false, prints a diagnostic + * message and aborts the program. + * + * + * FUTURE EXTENSIONS\n + * -----------------\n + * - advanced tracing functions to dump complex data + * - debug memory allocation that can be used to assist in + * finding memory problems + */ + + +#if !defined(__PICODBG_H__) +#define __PICODBG_H__ + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* Not all compilers support the __FUNCTION__ macro */ +#if !defined(__FUNCTION__) && !defined(__GNUC__) +#define __FUNCTION__ "" +#endif + + +/* Log levels sorted by severity */ +#define PICODBG_LOG_LEVEL_ERROR 1 +#define PICODBG_LOG_LEVEL_WARN 2 +#define PICODBG_LOG_LEVEL_INFO 3 +#define PICODBG_LOG_LEVEL_DEBUG 4 +#define PICODBG_LOG_LEVEL_TRACE 5 + +/* Output format flags */ +#define PICODBG_SHOW_LEVEL 0x0001 +#define PICODBG_SHOW_DATE 0x0002 +#define PICODBG_SHOW_TIME 0x0004 +#define PICODBG_SHOW_SRCNAME 0x0008 +#define PICODBG_SHOW_SRCLINE 0x0010 +#define PICODBG_SHOW_SRCALL (PICODBG_SHOW_SRCNAME | PICODBG_SHOW_SRCLINE) +#define PICODBG_SHOW_FUNCTION 0x0020 +#define PICODBG_SHOW_POS (PICODBG_SHOW_SRCALL | PICODBG_SHOW_FUNCTION) + +/* definition of PICO_DEBUG enables debugging code */ +#if defined(PICO_DEBUG) + +#define PICODBG_INITIALIZE(level) \ + picodbg_initialize(level) + +#define PICODBG_TERMINATE() \ + picodbg_terminate() + +#define PICODBG_SET_LOG_LEVEL(level) \ + picodbg_setLogLevel(level) + +#define PICODBG_SET_LOG_FILTERFN(name) \ + picodbg_setLogFilterFN(name) + +#define PICODBG_SET_LOG_FILE(name) \ + picodbg_setLogFile(name) + +#define PICODBG_ENABLE_COLORS(flag) \ + picodbg_enableColors(flag) + +#define PICODBG_SET_OUTPUT_FORMAT(format) \ + picodbg_setOutputFormat(format) + + +#define PICODBG_ASSERT(expr) \ + for (;!(expr);picodbg_assert(__FILE__, __LINE__, __FUNCTION__, #expr)) + +#define PICODBG_ASSERT_RANGE(val, min, max) \ + PICODBG_ASSERT(((val) >= (min)) && ((val) <= (max))) + + +#define PICODBG_LOG(level, msg) \ + picodbg_log(level, 1, __FILE__, __LINE__, __FUNCTION__, picodbg_varargs msg) + +#define PICODBG_ERROR(msg) \ + PICODBG_LOG(PICODBG_LOG_LEVEL_ERROR, msg) + +#define PICODBG_WARN(msg) \ + PICODBG_LOG(PICODBG_LOG_LEVEL_WARN, msg) + +#define PICODBG_INFO(msg) \ + PICODBG_LOG(PICODBG_LOG_LEVEL_INFO, msg) + +#define PICODBG_DEBUG(msg) \ + PICODBG_LOG(PICODBG_LOG_LEVEL_DEBUG, msg) + +#define PICODBG_TRACE(msg) \ + PICODBG_LOG(PICODBG_LOG_LEVEL_TRACE, msg) + + +#define PICODBG_INFO_CTX() \ + picodbg_log(PICODBG_LOG_LEVEL_INFO, 0, __FILE__, __LINE__, __FUNCTION__, "") + +#define PICODBG_INFO_MSG(msg) \ + picodbg_log_msg(PICODBG_LOG_LEVEL_INFO, __FILE__, picodbg_varargs msg) + +#define PICODBG_INFO_MSG_F(filterfn, msg) \ + picodbg_log_msg(PICODBG_LOG_LEVEL_INFO, (const char *)filterfn, picodbg_varargs msg) + + + +/* helper routines; should NOT be used directly! */ + +void picodbg_initialize(int level); +void picodbg_terminate(); + +void picodbg_setLogLevel(int level); +void picodbg_setLogFilterFN(const char *name); +void picodbg_setLogFile(const char *name); +void picodbg_enableColors(int flag); +void picodbg_setOutputFormat(unsigned int format); + +const char *picodbg_varargs(const char *format, ...); + +void picodbg_log(int level, int donewline, const char *file, int line, + const char *func, const char *msg); +void picodbg_assert(const char *file, int line, const char *func, + const char *expr); + +void picodbg_log_msg(int level, const char *file, const char *msg); + + +#else /* release version; omit debugging code */ + +#define PICODBG_INITIALIZE(level) +#define PICODBG_TERMINATE() +#define PICODBG_SET_LOG_LEVEL(level) +#define PICODBG_SET_LOG_FILTERFN(name) +#define PICODBG_SET_LOG_FILE(name) +#define PICODBG_ENABLE_COLORS(flag) +#define PICODBG_SET_OUTPUT_FORMAT(format) + +#define PICODBG_ASSERT(expr) +#define PICODBG_ASSERT_RANGE(val, min, max) + +#define PICODBG_LOG(level, msg) +#define PICODBG_ERROR(msg) +#define PICODBG_WARN(msg) +#define PICODBG_INFO(msg) +#define PICODBG_DEBUG(msg) +#define PICODBG_TRACE(msg) + +#define PICODBG_INFO_CTX() +#define PICODBG_INFO_MSG(msg) +#define PICODBG_INFO_MSG_F(filterfn, msg) + + +#endif /* defined(PICO_DEBUG) */ + +#ifdef __cplusplus +} +#endif + + +#endif /* !defined(__PICODBG_H__) */ diff --git a/pico/lib/picodefs.h b/pico/lib/picodefs.h new file mode 100644 index 0000000..24c59bd --- /dev/null +++ b/pico/lib/picodefs.h @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picodefs.h + * + * SVOX Pico definitions + * (SVOX Pico version 1.0 and later) + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + */ + + +#ifndef PICODEFS_H_ +#define PICODEFS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* ********************************************************************/ +/* SVOX Pico limits */ +/* ********************************************************************/ +/* maximum size of a voice name, including the terminating null + character */ +#define PICO_MAX_VOICE_NAME_SIZE 32 + +/* maximum size of a resource name, incl. the terminating null + character */ +#define PICO_MAX_RESOURCE_NAME_SIZE 32 + +/* maximum size of a data path name, incl. the terminating null + character */ +#define PICO_MAX_DATAPATH_NAME_SIZE 128 + +/* maximum size of a file name, incl. the terminating null + character */ +#define PICO_MAX_FILE_NAME_SIZE 64 + +/* maximum number of resources */ +#define PICO_MAX_NUM_RESOURCES 64 + +/* maximum number of voice definitions */ +#define PICO_MAX_NUM_VOICE_DEFINITIONS 64 + +/* maximum number of resources per voice */ +#define PICO_MAX_NUM_RSRC_PER_VOICE 16 + +/* maximum length of foreign header prepended to PICO resource files + (header length must be a multiple of 4 bytes) */ +#define PICO_MAX_FOREIGN_HEADER_LEN 64 + + + +/* ********************************************************************/ +/* SVOX PICO status codes */ +/* ********************************************************************/ + +typedef signed int pico_Status; + + +/* Okay ***************************************************************/ +/* functions return PICO_OK if all is okay */ + +#define PICO_OK (pico_Status) 0 + + +/* Exceptions and error codes *****************************************/ + +/* in case of exceptional events and errors (e.g. unexpected user + input) that disrupt the normal flow of operation, PICO_EXC_* or + PICO_ERR_* are returned. */ + +#define PICO_EXC_NUMBER_FORMAT (pico_Status) -10 +#define PICO_EXC_MAX_NUM_EXCEED (pico_Status) -11 +#define PICO_EXC_NAME_CONFLICT (pico_Status) -12 +#define PICO_EXC_NAME_UNDEFINED (pico_Status) -13 +#define PICO_EXC_NAME_ILLEGAL (pico_Status) -14 + +/* buffer interaction */ +#define PICO_EXC_BUF_OVERFLOW (pico_Status) -20 +#define PICO_EXC_BUF_UNDERFLOW (pico_Status) -21 +#define PICO_EXC_BUF_IGNORE (pico_Status) -22 + +/* internal memory handling */ +#define PICO_EXC_OUT_OF_MEM (pico_Status) -30 + +/* files */ +#define PICO_EXC_CANT_OPEN_FILE (pico_Status) -40 +#define PICO_EXC_UNEXPECTED_FILE_TYPE (pico_Status) -41 +#define PICO_EXC_FILE_CORRUPT (pico_Status) -42 +#define PICO_EXC_FILE_NOT_FOUND (pico_Status) -43 + +/* resources */ +#define PICO_EXC_RESOURCE_BUSY (pico_Status) -50 +#define PICO_EXC_RESOURCE_MISSING (pico_Status) -51 + +/* knowledge bases */ +#define PICO_EXC_KB_MISSING (pico_Status) -60 + +/* runtime exceptions */ +#define PICO_ERR_NULLPTR_ACCESS (pico_Status) -100 +#define PICO_ERR_INVALID_HANDLE (pico_Status) -101 +#define PICO_ERR_INVALID_ARGUMENT (pico_Status) -102 +#define PICO_ERR_INDEX_OUT_OF_RANGE (pico_Status) -103 + +/* other errors ("external" errors, e.g. hardware failure). */ +#define PICO_ERR_OTHER (pico_Status) -999 + + +/* Warnings ***********************************************************/ + +/* general */ +#define PICO_WARN_INCOMPLETE (pico_Status) 10 +#define PICO_WARN_FALLBACK (pico_Status) 11 +#define PICO_WARN_OTHER (pico_Status) 19 + +/* resources */ +#define PICO_WARN_KB_OVERWRITE (pico_Status) 50 +#define PICO_WARN_RESOURCE_DOUBLE_LOAD (pico_Status) 51 + +/* classifiers */ +#define PICO_WARN_INVECTOR (pico_Status) 60 +#define PICO_WARN_CLASSIFICATION (pico_Status) 61 +#define PICO_WARN_OUTVECTOR (pico_Status) 62 + +/* processing units */ +#define PICO_WARN_PU_IRREG_ITEM (pico_Status) 70 +#define PICO_WARN_PU_DISCARD_BUF (pico_Status) 71 + + + +/* ********************************************************************/ +/* Engine getData return values */ +/* ********************************************************************/ + +#define PICO_STEP_IDLE (pico_Status) 200 +#define PICO_STEP_BUSY (pico_Status) 201 + +#define PICO_STEP_ERROR (pico_Status) -200 + +/* ********************************************************************/ +/* resetEngine reset modes */ +/* ********************************************************************/ + +#define PICO_RESET_FULL 0 +#define PICO_RESET_SOFT 0x10 + + +/* ********************************************************************/ +/* Engine getData outDataType values */ +/* ********************************************************************/ + +/* 16 bit PCM samples, native endianness of platform */ +#define PICO_DATA_PCM_16BIT (pico_Int16) 1 + +#ifdef __cplusplus +} +#endif + + +#endif /*PICODEFS_H_*/ diff --git a/pico/lib/picodsp.h b/pico/lib/picodsp.h new file mode 100644 index 0000000..67457f8 --- /dev/null +++ b/pico/lib/picodsp.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picodsp.h + * + * Include file for DSP related data types and constants in Pico + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#ifndef PICODSP_H_ +#define PICODSP_H_ + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +/*----------------------------CONSTANTS ----------------------*/ +/*Normalization factors used at the start and at the end of the sig*/ +#define PICODSP_START_FLOAT_NORM 0.41f +#define PICODSP_ENVSPEC_K1 0.5f +#define PICODSP_ENVSPEC_K2 2 +#define PICODSP_GETEXC_K1 1024 +#define PICODSP_FIXRESP_NORM 4096.0f +#define PICODSP_END_FLOAT_NORM 1.5f*16.0f +#define PICODSP_FIX_SCALE1 0x4000000 +#define PICODSP_FIX_SCALE2 0x4000 +#define PICODSP_SHIFT_FACT1 10 +#define PICODSP_SHIFT_FACT2 16 +#define PICODSP_SHIFT_FACT3 12 +#define PICODSP_SHIFT_FACT4 1 +#define PICODSP_SHIFT_FACT5 18 +#define PICODSP_SHIFT_FACT6 9 +#define PICOSIG_NORM1 9.14f /100.0f /*normalization factor*/ +#define PICOSIG_MAXAMP (32767) +#define PICOSIG_MINAMP (-32768) +#define PICODSP_M_PI 3.14159265358979323846 +#define PICODSP_MAX_EX 32 +#define PICODSP_WGT_SHIFT (0x20000000) +#define PICODSP_N_RAND_TABLE (760) +#define PICODSP_COS_TABLE_LEN (512) +#define PICODSP_COS_TABLE_LEN2 (1024) +#define PICODSP_COS_TABLE_LEN4 (2048) +#define PICODSP_PI_SHIFT (4) /* -log2(PICODSP_COS_TABLE_LEN2/0x4000) */ + +#define PICODSP_V_CUTOFF_FREQ 4500 +#define PICODSP_UV_CUTOFF_FREQ 300 +#define PICODSP_SAMP_FREQ 16000 +#define PICODSP_FREQ_WARP_FACT 0.42f + +/*----------------------------CEP/PHASE CONSTANTS----------------------------*/ +#define PICODSP_CEPORDER 25 +#define PICODSP_PHASEORDER 72 +#define CEPST_BUFF_SIZE 3 +#define PHASE_BUFF_SIZE 5 +/*----------------------------FFT CONSTANTS----------------------------*/ +#define PICODSP_FFTSIZE (256) + +#define PICODSP_H_FFTSIZE (PICODSP_FFTSIZE/2) + +#define PICODSP_DISPLACE PICODSP_FFTSIZE/4 + +#define PICODSP_H_FFTSIZE (PICODSP_FFTSIZE/2) +#define PICODSP_HFFTSIZE_P1 (PICODSP_H_FFTSIZE+1) + +#define FAST_DEVICE(aCount, aAction) \ +{ \ + int count_ = (aCount); \ + int times_ = (count_ + 7) >> 3; \ + switch (count_ & 7){ \ + case 0: do { aAction; \ + case 7: aAction; \ + case 6: aAction; \ + case 5: aAction; \ + case 4: aAction; \ + case 3: aAction; \ + case 2: aAction; \ + case 1: aAction; \ + } while (--times_ > 0); \ +} \ +} +/*------------------------------------------------------------------------------------------ + Fast Exp Approximation now remapped to a function in picoos + -----------------------------------------------------------------------------------------*/ +#define EXP(y) picoos_quick_exp(y) + +#ifdef __cplusplus +} +#endif + +#endif /*PICODSP_H_*/ diff --git a/pico/lib/picoextapi.c b/pico/lib/picoextapi.c new file mode 100644 index 0000000..4c5d30c --- /dev/null +++ b/pico/lib/picoextapi.c @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picoextapi.c + * + * API extension for development use + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ +#include "picodefs.h" +#include "picoos.h" +#include "picoctrl.h" +#include "picodbg.h" +#include "picoapi.h" +#include "picoextapi.h" +#include "picoapid.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +/* this is not used anymore. For the picosh banner, set + * progv.progVers in picosh.c instead. */ +#define PICO_VERSION_INFO (picoos_char *)"invalid" + + +extern pico_Status pico_initialize_priv( + void *memory, + const pico_Uint32 size, + pico_Int16 enableMemProt, + pico_System *system); + + +/* System initialization and termination functions ****************************/ + + +PICO_FUNC picoext_initialize( + void *memory, + const pico_Uint32 size, + pico_Int16 enableMemProt, + pico_System *outSystem + ) +{ + return pico_initialize_priv(memory, size, enableMemProt, outSystem); +} + + +/* System and lingware inspection functions ***********************************/ + +/* @todo : not supported yet */ +PICO_FUNC picoext_getVersionInfo( + pico_Retstring outInfo, + const pico_Int16 outInfoMaxLen + ) +{ + if (outInfo == NULL) { + return PICO_ERR_NULLPTR_ACCESS; + } + picoos_strlcpy((picoos_char *) outInfo, PICO_VERSION_INFO, outInfoMaxLen); + return PICO_OK; +} + + +/* Debugging/testing support functions *****************************************/ + + +PICO_FUNC picoext_setTraceLevel( + pico_System system, + pico_Int32 level + ) +{ + if (NULL == system) { + return PICO_ERR_NULLPTR_ACCESS; + } + if (level < 0) { + level = 0; + } + if (level > PICODBG_LOG_LEVEL_TRACE) { + level = PICODBG_LOG_LEVEL_TRACE; + } + PICODBG_SET_LOG_LEVEL(level); + return PICO_OK; +} + + +PICO_FUNC picoext_setTraceFilterFN( + pico_System system, + const pico_Char *name + ) +{ + + if (NULL == system) { + return PICO_ERR_NULLPTR_ACCESS; + } + name = name; /*PP 13.10.08 : fix warning "var not used in this function"*/ + PICODBG_SET_LOG_FILTERFN((const char *)name); + return PICO_OK; +} + + +PICO_FUNC picoext_setLogFile( + pico_System system, + const pico_Char *name + ) +{ + if (NULL == system) { + return PICO_ERR_NULLPTR_ACCESS; + } + name = name; /*PP 13.10.08 : fix warning "var not used in this function"*/ + PICODBG_SET_LOG_FILE((const char *) name); + return PICO_OK; +} + + +/* Memory usage ***************************************************************/ + + +pico_Status getMemUsage( + picoos_Common common, + picoos_bool resetIncremental, + picoos_int32 *usedBytes, + picoos_int32 *incrUsedBytes, + picoos_int32 *maxUsedBytes + ) +{ + pico_Status status = PICO_OK; + + if (common == NULL) { + status = PICO_ERR_NULLPTR_ACCESS; + } else { + picoos_emReset(common->em); + picoos_getMemUsage(common->mm, resetIncremental, usedBytes, incrUsedBytes, maxUsedBytes); + status = picoos_emGetExceptionCode(common->em); + } + + return status; +} + + +PICO_FUNC picoext_getSystemMemUsage( + pico_System system, + pico_Int16 resetIncremental, + pico_Int32 *outUsedBytes, + pico_Int32 *outIncrUsedBytes, + pico_Int32 *outMaxUsedBytes + ) +{ + pico_Status status = PICO_OK; + + if (!is_valid_system_handle(system)) { + status = PICO_ERR_INVALID_HANDLE; + } else if ((outUsedBytes == NULL) || (outIncrUsedBytes == NULL) || (outMaxUsedBytes == NULL)) { + status = PICO_ERR_NULLPTR_ACCESS; + } else { + picoos_Common common = pico_sysGetCommon(system); + status = getMemUsage(common, resetIncremental != 0, outUsedBytes, outIncrUsedBytes, outMaxUsedBytes); + } + + return status; +} + + +PICO_FUNC picoext_getEngineMemUsage( + pico_Engine engine, + pico_Int16 resetIncremental, + pico_Int32 *outUsedBytes, + pico_Int32 *outIncrUsedBytes, + pico_Int32 *outMaxUsedBytes + ) +{ + pico_Status status = PICO_OK; + + if (!picoctrl_isValidEngineHandle((picoctrl_Engine) engine)) { + status = PICO_ERR_INVALID_HANDLE; + } else if ((outUsedBytes == NULL) || (outIncrUsedBytes == NULL) || (outMaxUsedBytes == NULL)) { + status = PICO_ERR_NULLPTR_ACCESS; + } else { + picoos_Common common = picoctrl_engGetCommon((picoctrl_Engine) engine); + status = getMemUsage(common, resetIncremental != 0, outUsedBytes, outIncrUsedBytes, outMaxUsedBytes); + } + + return status; +} + +PICO_FUNC picoext_getLastScheduledPU( + pico_Engine engine + ) +{ + pico_Status status = PICO_OK; + status = picoctrl_getLastScheduledPU((picoctrl_Engine) engine); + return status; +} + +PICO_FUNC picoext_getLastProducedItemType( + pico_Engine engine + ) +{ + pico_Status status = PICO_OK; + status = picoctrl_getLastProducedItemType((picoctrl_Engine) engine); + return status; +} + +#ifdef __cplusplus +} +#endif + +/* end */ diff --git a/pico/lib/picoextapi.h b/pico/lib/picoextapi.h new file mode 100644 index 0000000..1768394 --- /dev/null +++ b/pico/lib/picoextapi.h @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picoextapi.h + * + * API extensions for development use + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#ifndef PICOEXTAPI_H_ +#define PICOEXTAPI_H_ + +#include "picodefs.h" +#include "picodbg.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* ****************************************************************************/ +/* Things that might be added to picoapi later but should not appear there */ +/* for the time being */ +/* ****************************************************************************/ + +/* String type for Unicode text input *****************************************/ + +/* Unicode encodings supported by PICO. */ + +#define PICO_STRENC_UTF8 0 +#define PICO_STRENC_UTF16 1 + +/* An UTF-8 string must point to a byte array, terminated by a null character + ('\0'). An UTF-16 string must point to a contiguous array of 16-bit units + (in native byte ordering), terminated by a 0. */ + +typedef char *PICO_STRING_UTF8; +typedef pico_Uint16 *PICO_STRING_UTF16; + +/* Generic pointer to a Unicode string, encoded either as UTF-8 or UTF-16. + The application must make sure that for each 'PICO_STRING_PTR' it provides + an argument of type 'PICO_STRING_UTF8' or 'PICO_STRING_UTF16' (or of a type + compatible to one of these types). */ + +typedef void *PICO_STRING_PTR; + + +/* ****************************************************************************/ +/* System-level API functions */ +/* ****************************************************************************/ + +/* System initialization and termination functions ****************************/ + +/* Same as pico_initialize, but allows to enable memory protection + functionality for testing purposes (enableMemProt != 0). */ + +PICO_FUNC picoext_initialize( + void *memory, + const pico_Uint32 size, + pico_Int16 enableMemProt, + pico_System *outSystem + ); + + +/* System and lingware inspection functions ***********************************/ + +/* Returns version information of the current Pico engine. */ + +PICO_FUNC picoext_getVersionInfo( + pico_Retstring outInfo, + const pico_Int16 outInfoMaxLen + ); + +/* Returns unique resource name */ + +/* +PICO_FUNC picoext_getResourceName( + pico_Resource resource, + pico_Retstring outInfo + ); +*/ + +/* Debugging/testing support functions *****************************************/ + +/* Sets tracing level. Increasing amounts of information is displayed + at each level. */ + +PICO_FUNC picoext_setTraceLevel( + pico_System system, + pico_Int32 level + ); + +/* Sets trace filtering. Limits tracing output to tracing information + resulting from the source file name being filtered. */ + +PICO_FUNC picoext_setTraceFilterFN( + pico_System system, + const pico_Char *name + ); + +/* Enables logging of debug output to log file 'name'. If 'name' is NULL + or an empty string, logging is disabled. */ + +PICO_FUNC picoext_setLogFile( + pico_System system, + const pico_Char *name + ); + + +/* Memory usage ***************************************************************/ + +PICO_FUNC picoext_getSystemMemUsage( + pico_System system, + pico_Int16 resetIncremental, + pico_Int32 *outUsedBytes, + pico_Int32 *outIncrUsedBytes, + pico_Int32 *outMaxUsedBytes + ); + +PICO_FUNC picoext_getEngineMemUsage( + pico_Engine engine, + pico_Int16 resetIncremental, + pico_Int32 *outUsedBytes, + pico_Int32 *outIncrUsedBytes, + pico_Int32 *outMaxUsedBytes + ); + +PICO_FUNC picoext_getLastScheduledPU( + pico_Engine engine + ); + +PICO_FUNC picoext_getLastProducedItemType( + pico_Engine engine + ); + +#ifdef __cplusplus +} +#endif + + +#endif /* PICOEXTAPI_H_ */ diff --git a/pico/lib/picofftsg.c b/pico/lib/picofftsg.c new file mode 100644 index 0000000..dcca018 --- /dev/null +++ b/pico/lib/picofftsg.c @@ -0,0 +1,3274 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picofftsg.c + * + * FFT/DCT related data types, constants and functions in Pico + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * +*/ + +#include "picoos.h" +#include "picofftsg.h" +#include "picodbg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup picofft + * ---------------------------------------------------\n + * Fast Fourier/Cosine/Sine Transform \n + * Adapted from http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html (Copyright Takuya OOURA, 1996-2001)\n + * ---------------------------------------------------\n + + Overall features + - dimension :one + - data length :power of 2 + - decimation :frequency + - radix :split-radix + - data :inplace + - table :not use + + functions + - cdft: Complex Discrete Fourier Transform + - rdft: Real Discrete Fourier Transform + - ddct: Discrete Cosine Transform + - ddst: Discrete Sine Transform + - dfct: Cosine Transform of RDFT (Real Symmetric DFT) + - dfst: Sine Transform of RDFT (Real Anti-symmetric DFT) + + function prototypes + - void cdft(picoos_int32, picoos_int32, PICOFFTSG_FFTTYPE *); + - void rdft(picoos_int32, picoos_int32, PICOFFTSG_FFTTYPE *); + - void ddct(picoos_int32, picoos_int32, PICOFFTSG_FFTTYPE *); + - void ddst(picoos_int32, picoos_int32, PICOFFTSG_FFTTYPE *); + - void dfct(picoos_int32, PICOFFTSG_FFTTYPE *); + - void dfst(picoos_int32, PICOFFTSG_FFTTYPE *); + + Complex DFT (Discrete Fourier Transform) + + [definition] + - + - X[k] = sum_j=0^n-1 x[j]*exp(2*pi*i*j*k/n), 0<=k + - X[k] = sum_j=0^n-1 x[j]*exp(-2*pi*i*j*k/n), 0<=k + - cdft(2*n, 1, a); + - + - cdft(2*n, -1, a); + + [parameters] + - 2*n :data length (picoos_int32) + - n >= 1, n = power of 2 + - a[0...2*n-1] :input/output data (PICOFFTSG_FFTTYPE *) + - input data + - a[2*j] = Re(x[j]), + - a[2*j+1] = Im(x[j]), 0<=j Real DFT / Inverse of Real DFT + + [definition] + - RDFT + - R[k] = sum_j=0^n-1 a[j]*cos(2*pi*j*k/n), 0<=k<=n/2 + - I[k] = sum_j=0^n-1 a[j]*sin(2*pi*j*k/n), 0 IRDFT (excluding scale) + - a[k] = (R[0] + R[n/2]*cos(pi*k))/2 + + - sum_j=1^n/2-1 R[j]*cos(2*pi*j*k/n) + + - sum_j=1^n/2-1 I[j]*sin(2*pi*j*k/n), 0<=k + - rdft(n, 1, a); + - + - rdft(n, -1, a); + + [parameters] + - n :data length (picoos_int32) + - n >= 2, n = power of 2 + - a[0...n-1] :input/output data (PICOFFTSG_FFTTYPE *) + - + - output data + - a[2*k] = R[k], 0<=k + - input data + - a[2*j] = R[j], 0<=j DCT (Discrete Cosine Transform) / Inverse of DCT + + [definition] + - IDCT (excluding scale) + - C[k] = sum_j=0^n-1 a[j]*cos(pi*j*(k+1/2)/n), 0<=k DCT + - C[k] = sum_j=0^n-1 a[j]*cos(pi*(j+1/2)*k/n), 0<=k + - ddct(n, 1, a); + - + - ddct(n, -1, a); + + [parameters] + - n :data length (picoos_int32) + - n >= 2, n = power of 2 + - a[0...n-1] :input/output data (PICOFFTSG_FFTTYPE *) + - output data + - a[k] = C[k], 0<=k DST (Discrete Sine Transform) / Inverse of DST + + [definition] + - IDST (excluding scale) + - S[k] = sum_j=1^n A[j]*sin(pi*j*(k+1/2)/n), 0<=k DST + - S[k] = sum_j=0^n-1 a[j]*sin(pi*(j+1/2)*k/n), 0 + - ddst(n, 1, a); + - + - ddst(n, -1, a); + + [parameters] + - n :data length (picoos_int32) + - n >= 2, n = power of 2 + - a[0...n-1] :input/output data (PICOFFTSG_FFTTYPE *) + - + - input data + - a[j] = A[j], 0 + - output data + - a[k] = S[k], 0 Cosine Transform of RDFT (Real Symmetric DFT) + + [definition] + - C[k] = sum_j=0^n a[j]*cos(pi*j*k/n), 0<=k<=n + + [usage] + - dfct(n, a); + + [parameters] + - n :data length - 1 (picoos_int32) + - n >= 2, n = power of 2 + - a[0...n] :input/output data (PICOFFTSG_FFTTYPE *) + + - output data + - a[k] = C[k], 0<=k<=n + + [remark] + - Inverse of a[0] *= 0.5; a[n] *= 0.5; dfct(n, a); is + - a[0] *= 0.5; + - a[n] *= 0.5; + - dfct(n, a); + - for (j = 0; j <= n; j++) { + - a[j] *= 2.0 / n; + - } + + Sine Transform of RDFT (Real Anti-symmetric DFT) + + [definition] + - S[k] = sum_j=1^n-1 a[j]*sin(pi*j*k/n), 0= 2, n = power of 2 + - a[0...n-1] :input/output data (PICOFFTSG_FFTTYPE *) + - output data + - a[k] = S[k], 0=POW17?(x>=POW25?(x>=POW29?(x>=POW31?31:(x>=POW30?30:29)):(x>=POW27?(x>=POW28?28:27):(x>=POW26?26:25))):(x>=POW21?(x>=POW23?(x>=POW24?24:23):(x>=POW22?22:21)):(x>=POW19?(x>=POW20?20:19):(x>=POW18?18:17)))):(x>=POW9?(x>=POW13?(x>=POW15?(x>=POW16?16:15):(x>=POW14?14:13)):(x>=POW11?(x>=POW12?12:11):(x>=POW10?10:9))):(x>=POW5?(x>=POW7?(x>=POW8?8:7):(x>=POW6?6:5)):(x>=POW3?(x>=POW4?4:3):(x>=POW2?2:1)))))) +#define picofftsg_highestBit(x) (x==0?0:(x<0?(zz=-x,(zz>=POW17?(zz>=POW25?(zz>=POW29?(zz>=POW31?31:(zz>=POW30?30:29)):(zz>=POW27?(zz>=POW28?28:27):(zz>=POW26?26:25))):(zz>=POW21?(zz>=POW23?(zz>=POW24?24:23):(zz>=POW22?22:21)):(zz>=POW19?(zz>=POW20?20:19):(zz>=POW18?18:17)))):(zz>=POW9?(zz>=POW13?(zz>=POW15?(zz>=POW16?16:15):(zz>=POW14?14:13)):(zz>=POW11?(zz>=POW12?12:11):(zz>=POW10?10:9))):(zz>=POW5?(zz>=POW7?(zz>=POW8?8:7):(zz>=POW6?6:5)):(zz>=POW3?(zz>=POW4?4:3):(zz>=POW2?2:1)))))):(x>=POW17?(x>=POW25?(x>=POW29?(x>=POW31?31:(x>=POW30?30:29)):(x>=POW27?(x>=POW28?28:27):(x>=POW26?26:25))):(x>=POW21?(x>=POW23?(x>=POW24?24:23):(x>=POW22?22:21)):(x>=POW19?(x>=POW20?20:19):(x>=POW18?18:17)))):(x>=POW9?(x>=POW13?(x>=POW15?(x>=POW16?16:15):(x>=POW14?14:13)):(x>=POW11?(x>=POW12?12:11):(x>=POW10?10:9))):(x>=POW5?(x>=POW7?(x>=POW8?8:7):(x>=POW6?6:5)):(x>=POW3?(x>=POW4?4:3):(x>=POW2?2:1))))))) +#define Mult_W_W picofftsg_mult_w_w + + +/* ***********************************************************************************************/ +/* forward declarations */ +/* ***********************************************************************************************/ +static PICOFFTSG_FFTTYPE picofftsg_mult_w_w(PICOFFTSG_FFTTYPE x1, PICOFFTSG_FFTTYPE y1); +static PICOFFTSG_FFTTYPE picofftsg_mult_w_a(PICOFFTSG_FFTTYPE x1, PICOFFTSG_FFTTYPE y1); + + +static void cftfsub(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +static void cftbsub(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +static void rftfsub(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +static void rftbsub(picoos_int32 n, PICOFFTSG_FFTTYPE *a); + +static void cftfsub(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +static void cftbsub(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +static void rftfsub(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +static void rftbsub(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +static void dctsub(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +static void dctsub4(picoos_int32 n, PICOFFTSG_FFTTYPE *a); + +static void ddct(picoos_int32 n, picoos_int32 isgn, PICOFFTSG_FFTTYPE *a); +static void bitrv1(picoos_int32 n, PICOFFTSG_FFTTYPE *a); + +static void bitrv2(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +static void bitrv216(PICOFFTSG_FFTTYPE *a); +static void bitrv208(PICOFFTSG_FFTTYPE *a); +static void cftmdl1(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +static void cftrec4(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +static void cftleaf(picoos_int32 n, picoos_int32 isplt, PICOFFTSG_FFTTYPE *a); +static void cftfx41(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +static void cftf161(PICOFFTSG_FFTTYPE *a); +static void cftf081(PICOFFTSG_FFTTYPE *a); +static void cftf040(PICOFFTSG_FFTTYPE *a); +static void cftx020(PICOFFTSG_FFTTYPE *a); + +void bitrv2conj(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +void bitrv216neg(PICOFFTSG_FFTTYPE *a); +void bitrv208neg(PICOFFTSG_FFTTYPE *a); +void cftb1st(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +void cftrec4(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +void cftleaf(picoos_int32 n, picoos_int32 isplt, PICOFFTSG_FFTTYPE *a); +void cftfx41(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +void cftf161(PICOFFTSG_FFTTYPE *a); +void cftf081(PICOFFTSG_FFTTYPE *a); +void cftb040(PICOFFTSG_FFTTYPE *a); +void cftx020(PICOFFTSG_FFTTYPE *a); + +static picoos_int32 cfttree(picoos_int32 n, picoos_int32 j, picoos_int32 k, PICOFFTSG_FFTTYPE *a); +static void cftleaf(picoos_int32 n, picoos_int32 isplt, PICOFFTSG_FFTTYPE *a); +static void cftmdl1(picoos_int32 n, PICOFFTSG_FFTTYPE *a); + +static void cftmdl1(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +static void cftmdl2(picoos_int32 n, PICOFFTSG_FFTTYPE *a); + +static void cftmdl1(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +static void cftmdl2(picoos_int32 n, PICOFFTSG_FFTTYPE *a); +static void cftf161(PICOFFTSG_FFTTYPE *a); +static void cftf162(PICOFFTSG_FFTTYPE *a); +static void cftf081(PICOFFTSG_FFTTYPE *a); +static void cftf082(PICOFFTSG_FFTTYPE *a); + +static void cftf161(PICOFFTSG_FFTTYPE *a); +static void cftf162(PICOFFTSG_FFTTYPE *a); +static void cftf081(PICOFFTSG_FFTTYPE *a); +static void cftf082(PICOFFTSG_FFTTYPE *a); + +/* ***********************************************************************************************/ +/* Exported functions */ +/* ***********************************************************************************************/ +void rdft(picoos_int32 n, picoos_int32 isgn, PICOFFTSG_FFTTYPE *a) +{ + PICOFFTSG_FFTTYPE xi; + + if (isgn >= 0) { + if (n > 4) { + cftfsub(n, a); + rftfsub(n, a); + } else if (n == 4) { + cftfsub(n, a); + } + xi = a[0] - a[1]; + a[0] += a[1]; + a[1] = xi; + } else { + a[1] = (a[0] - a[1]) / 2; + a[0] -= a[1]; + if (n > 4) { + rftbsub(n, a); + cftbsub(n, a); + } else if (n == 4) { + cftbsub(n, a); + } + } + +} + + +picoos_single norm_result(picoos_int32 m2, PICOFFTSG_FFTTYPE *tmpX, PICOFFTSG_FFTTYPE *norm_window) +{ + picoos_int16 nI; + PICOFFTSG_FFTTYPE a,b, E; + + E = (picoos_int32)0; + for (nI=0; nI>18) * ((tmpX[nI]>0) ? tmpX[nI]>>11 : -((-tmpX[nI])>>11)); + tmpX[nI] = a; + b = (a>=0?a:-a) >> 18; + E += (b*b); + } + + if (E>0) { + return (picoos_single)sqrt((double)E/16.0)/m2; + } + else { + return 0.0; + } +} + +void ddct(picoos_int32 n, picoos_int32 isgn, PICOFFTSG_FFTTYPE *a) +{ + picoos_int32 j; + PICOFFTSG_FFTTYPE xr; + + if (isgn < 0) { + xr = a[n - 1]; + for (j = n - 2; j >= 2; j -= 2) { + a[j + 1] = a[j] - a[j - 1]; + a[j] += a[j - 1]; + } + a[1] = a[0] - xr; + a[0] += xr; + if (n > 4) { + rftbsub(n, a); + cftbsub(n, a); + } else if (n == 4) { + cftbsub(n, a); + } + } + if (n > 4) { + dctsub(n, a); + } else { + dctsub4(n, a); + } + if (isgn >= 0) { + if (n > 4) { + cftfsub(n, a); + rftfsub(n, a); + } else if (n == 4) { + cftfsub(n, a); + } + + + xr = a[0] - a[1]; + a[0] += a[1]; + for (j = 2; j < n; j += 2) { + a[j - 1] = a[j] - a[j + 1]; + a[j] += a[j + 1]; + } + a[n - 1] = xr; + } +} + +void dfct_nmf(picoos_int32 n, picoos_int32 *a) +{ + picoos_int32 j, k, m, mh; + PICOFFTSG_FFTTYPE xr, xi, yr, yi, an; + PICOFFTSG_FFTTYPE *aj, *ak, *amj, *amk; + + m = n >> 1; + for (j = 0; j < m; j++) { + k = n - j; + xr = a[j] + a[k]; + a[j] -= a[k]; + a[k] = xr; + } + an = a[n]; + while (m >= 2) { + ddct(m, 1, a); + if (m > 2) { + bitrv1(m, a); + } + mh = m >> 1; + xi = a[m]; + a[m] = a[0]; + a[0] = an - xi; + an += xi; + k = m-1; + aj = a + 1; ak = a + k; amj = aj + m; amk = ak + m; + for (j = 1; j < mh; j++, aj++, ak--, amj++, amk--) { + xr = *amk; + xi = *amj; + yr = *aj; + yi = *ak; + *amj = yr; + *amk = yi; + *aj = xr - xi; + *ak = xr + xi; + } + xr = *aj; + *aj = *amj; + *amj = xr; + + m = mh; + } + + xi = a[1]; + a[1] = a[0]; + a[0] = an + xi; + a[n] = an - xi; + if (n > 2) { + bitrv1(n, a); + } + +} + +/* ***********************************************************************************************/ +/* internal routines */ +/* ***********************************************************************************************/ +/* + mult two numbers which are guaranteed to be in the range -1..1 + shift right as little as possible before mult, and the rest after the mult + Also, shift bigger number more - lose less accuracy + */ +static PICOFFTSG_FFTTYPE picofftsg_mult_w_w(PICOFFTSG_FFTTYPE x1, PICOFFTSG_FFTTYPE y1) +{ + PICOFFTSG_FFTTYPE x, y; + x = x1>=0 ? x1>>15 : -((-x1)>>15); + y = y1>=0 ? y1>>14 : -((-y1)>>14); + return x * y; +} + +static PICOFFTSG_FFTTYPE picofftsg_mult_w_a(PICOFFTSG_FFTTYPE x1, PICOFFTSG_FFTTYPE y1) +{ + PICOFFTSG_FFTTYPE x, y; + + + x = x1>=0 ? x1>>15 : -((-x1)>>15); + y = y1>=0 ? y1>>14 : -((-y1)>>14); + return x * y; +} + +static void cftfsub(picoos_int32 n, PICOFFTSG_FFTTYPE *a) +{ + + if (n > 8) { + if (n > 32) { + cftmdl1(n, a); + if (n > 512) { + cftrec4(n, a); + } else if (n > 128) { + cftleaf(n, 1, a); + } else { + cftfx41(n, a); + } + bitrv2(n, a); + } else if (n == 32) { + cftf161(a); + bitrv216(a); + } else { + cftf081(a); + bitrv208(a); + } + } else if (n == 8) { + cftf040(a); + } else if (n == 4) { + cftx020(a); + } +} + + +void cftbsub(picoos_int32 n, PICOFFTSG_FFTTYPE *a) +{ + if (n > 8) { + if (n > 32) { + cftb1st(n, a); + if (n > 512) { + cftrec4(n, a); + } else if (n > 128) { + cftleaf(n, 1, a); + } else { + cftfx41(n, a); + } + bitrv2conj(n, a); + } else if (n == 32) { + cftf161(a); + bitrv216neg(a); + } else { + cftf081(a); + bitrv208neg(a); + } + } else if (n == 8) { + cftb040(a); + } else if (n == 4) { + cftx020(a); + } +} + +/* **************************************************************************************************/ + +/* **************************************************************************************************/ +void bitrv2(picoos_int32 n, PICOFFTSG_FFTTYPE *a) +{ + picoos_int32 j0, k0, j1, k1, l, m, i, j, k, nh, m2; + PICOFFTSG_FFTTYPE xr, xi, yr, yi; + + m = 4; + for (l = n >> 2; l > 8; l >>= 2) { + m <<= 1; + } + m2 = m + m; + nh = n >> 1; + if (l == 8) { + j0 = 0; + for (k0 = 0; k0 < m; k0 += 4) { + k = k0; + for (j = j0; j < j0 + k0; j += 4) { + xr = a[j]; + xi = a[j + 1]; + yr = a[k]; + yi = a[k + 1]; + a[j] = yr; + a[j + 1] = yi; + a[k] = xr; + a[k + 1] = xi; + j1 = j + m; + k1 = k + m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 -= m; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 += m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nh; + k1 += 2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= m; + k1 -= m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= m; + k1 += m; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= m; + k1 -= m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += 2; + k1 += nh; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 += m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 -= m; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 += m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nh; + k1 -= 2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= m; + k1 -= m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= m; + k1 += m; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= m; + k1 -= m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + for (i = nh >> 1; i > (k ^= i); i >>= 1) { + /* Avoid warning*/ + }; + } + k1 = j0 + k0; + j1 = k1 + 2; + k1 += nh; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 += m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 -= m; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= 2; + k1 -= nh; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nh + 2; + k1 += nh + 2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nh - m; + k1 += m2 - 2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + for (i = nh >> 1; i > (j0 ^= i); i >>= 1) { + /* Avoid warning */ + } + } + } else { + j0 = 0; + for (k0 = 0; k0 < m; k0 += 4) { + k = k0; + for (j = j0; j < j0 + k0; j += 4) { + xr = a[j]; + xi = a[j + 1]; + yr = a[k]; + yi = a[k + 1]; + a[j] = yr; + a[j + 1] = yi; + a[k] = xr; + a[k + 1] = xi; + j1 = j + m; + k1 = k + m; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nh; + k1 += 2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= m; + k1 -= m; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += 2; + k1 += nh; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 += m; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nh; + k1 -= 2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= m; + k1 -= m; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + for (i = nh >> 1; i > (k ^= i); i >>= 1){ + /* Avoid warning */ + } + } + k1 = j0 + k0; + j1 = k1 + 2; + k1 += nh; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 += m; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + for (i = nh >> 1; i > (j0 ^= i); i >>= 1){ + /* Avoid warning */ + } + } + } +} + + +void bitrv2conj(picoos_int32 n, PICOFFTSG_FFTTYPE *a) +{ + picoos_int32 j0, k0, j1, k1, l, m, i, j, k, nh, m2; + PICOFFTSG_FFTTYPE xr, xi, yr, yi; + + + m = 4; + for (l = n >> 2; l > 8; l >>= 2) { + m <<= 1; + } + m2 = m + m; + nh = n >> 1; + if (l == 8) { + j0 = 0; + for (k0 = 0; k0 < m; k0 += 4) { + k = k0; + for (j = j0; j < j0 + k0; j += 4) { + xr = a[j]; + xi = -a[j + 1]; + yr = a[k]; + yi = -a[k + 1]; + a[j] = yr; + a[j + 1] = yi; + a[k] = xr; + a[k + 1] = xi; + j1 = j + m; + k1 = k + m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 -= m; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 += m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nh; + k1 += 2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= m; + k1 -= m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= m; + k1 += m; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= m; + k1 -= m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += 2; + k1 += nh; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 += m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 -= m; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 += m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nh; + k1 -= 2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= m; + k1 -= m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= m; + k1 += m; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= m; + k1 -= m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + for (i = nh >> 1; i > (k ^= i); i >>= 1) { + /* Avoid warning */ + } + } + k1 = j0 + k0; + j1 = k1 + 2; + k1 += nh; + a[j1 - 1] = -a[j1 - 1]; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + a[k1 + 3] = -a[k1 + 3]; + j1 += m; + k1 += m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 -= m; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= 2; + k1 -= nh; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nh + 2; + k1 += nh + 2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nh - m; + k1 += m2 - 2; + a[j1 - 1] = -a[j1 - 1]; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + a[k1 + 3] = -a[k1 + 3]; + for (i = nh >> 1; i > (j0 ^= i); i >>= 1) { /* Avoid warning*/ + + } + } + } else { + j0 = 0; + for (k0 = 0; k0 < m; k0 += 4) { + k = k0; + for (j = j0; j < j0 + k0; j += 4) { + xr = a[j]; + xi = -a[j + 1]; + yr = a[k]; + yi = -a[k + 1]; + a[j] = yr; + a[j + 1] = yi; + a[k] = xr; + a[k + 1] = xi; + j1 = j + m; + k1 = k + m; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += nh; + k1 += 2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= m; + k1 -= m; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += 2; + k1 += nh; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m; + k1 += m; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= nh; + k1 -= 2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 -= m; + k1 -= m; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + for (i = nh >> 1; i > (k ^= i); i >>= 1) { + /* Avoid warning*/ + } + } + k1 = j0 + k0; + j1 = k1 + 2; + k1 += nh; + a[j1 - 1] = -a[j1 - 1]; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + a[k1 + 3] = -a[k1 + 3]; + j1 += m; + k1 += m; + a[j1 - 1] = -a[j1 - 1]; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + a[k1 + 3] = -a[k1 + 3]; + for (i = nh >> 1; i > (j0 ^= i); i >>= 1) { + /* Avoid warning*/ + } + } + } +} + + +void bitrv216(PICOFFTSG_FFTTYPE *a) +{ + PICOFFTSG_FFTTYPE x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i, + x5r, x5i, x7r, x7i, x8r, x8i, x10r, x10i, + x11r, x11i, x12r, x12i, x13r, x13i, x14r, x14i; + + x1r = a[2]; + x1i = a[3]; + x2r = a[4]; + x2i = a[5]; + x3r = a[6]; + x3i = a[7]; + x4r = a[8]; + x4i = a[9]; + x5r = a[10]; + x5i = a[11]; + x7r = a[14]; + x7i = a[15]; + x8r = a[16]; + x8i = a[17]; + x10r = a[20]; + x10i = a[21]; + x11r = a[22]; + x11i = a[23]; + x12r = a[24]; + x12i = a[25]; + x13r = a[26]; + x13i = a[27]; + x14r = a[28]; + x14i = a[29]; + a[2] = x8r; + a[3] = x8i; + a[4] = x4r; + a[5] = x4i; + a[6] = x12r; + a[7] = x12i; + a[8] = x2r; + a[9] = x2i; + a[10] = x10r; + a[11] = x10i; + a[14] = x14r; + a[15] = x14i; + a[16] = x1r; + a[17] = x1i; + a[20] = x5r; + a[21] = x5i; + a[22] = x13r; + a[23] = x13i; + a[24] = x3r; + a[25] = x3i; + a[26] = x11r; + a[27] = x11i; + a[28] = x7r; + a[29] = x7i; +} + + +void bitrv216neg(PICOFFTSG_FFTTYPE *a) +{ + PICOFFTSG_FFTTYPE x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i, + x5r, x5i, x6r, x6i, x7r, x7i, x8r, x8i, + x9r, x9i, x10r, x10i, x11r, x11i, x12r, x12i, + x13r, x13i, x14r, x14i, x15r, x15i; + + x1r = a[2]; + x1i = a[3]; + x2r = a[4]; + x2i = a[5]; + x3r = a[6]; + x3i = a[7]; + x4r = a[8]; + x4i = a[9]; + x5r = a[10]; + x5i = a[11]; + x6r = a[12]; + x6i = a[13]; + x7r = a[14]; + x7i = a[15]; + x8r = a[16]; + x8i = a[17]; + x9r = a[18]; + x9i = a[19]; + x10r = a[20]; + x10i = a[21]; + x11r = a[22]; + x11i = a[23]; + x12r = a[24]; + x12i = a[25]; + x13r = a[26]; + x13i = a[27]; + x14r = a[28]; + x14i = a[29]; + x15r = a[30]; + x15i = a[31]; + a[2] = x15r; + a[3] = x15i; + a[4] = x7r; + a[5] = x7i; + a[6] = x11r; + a[7] = x11i; + a[8] = x3r; + a[9] = x3i; + a[10] = x13r; + a[11] = x13i; + a[12] = x5r; + a[13] = x5i; + a[14] = x9r; + a[15] = x9i; + a[16] = x1r; + a[17] = x1i; + a[18] = x14r; + a[19] = x14i; + a[20] = x6r; + a[21] = x6i; + a[22] = x10r; + a[23] = x10i; + a[24] = x2r; + a[25] = x2i; + a[26] = x12r; + a[27] = x12i; + a[28] = x4r; + a[29] = x4i; + a[30] = x8r; + a[31] = x8i; +} + + +void bitrv208(PICOFFTSG_FFTTYPE *a) +{ + PICOFFTSG_FFTTYPE x1r, x1i, x3r, x3i, x4r, x4i, x6r, x6i; + + x1r = a[2]; + x1i = a[3]; + x3r = a[6]; + x3i = a[7]; + x4r = a[8]; + x4i = a[9]; + x6r = a[12]; + x6i = a[13]; + a[2] = x4r; + a[3] = x4i; + a[6] = x6r; + a[7] = x6i; + a[8] = x1r; + a[9] = x1i; + a[12] = x3r; + a[13] = x3i; +} + + +void bitrv208neg(PICOFFTSG_FFTTYPE *a) +{ + PICOFFTSG_FFTTYPE x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i, + x5r, x5i, x6r, x6i, x7r, x7i; + + x1r = a[2]; + x1i = a[3]; + x2r = a[4]; + x2i = a[5]; + x3r = a[6]; + x3i = a[7]; + x4r = a[8]; + x4i = a[9]; + x5r = a[10]; + x5i = a[11]; + x6r = a[12]; + x6i = a[13]; + x7r = a[14]; + x7i = a[15]; + a[2] = x7r; + a[3] = x7i; + a[4] = x3r; + a[5] = x3i; + a[6] = x5r; + a[7] = x5i; + a[8] = x1r; + a[9] = x1i; + a[10] = x6r; + a[11] = x6i; + a[12] = x2r; + a[13] = x2i; + a[14] = x4r; + a[15] = x4i; +} + + +void bitrv1(picoos_int32 n, PICOFFTSG_FFTTYPE *a) +{ + picoos_int32 j0, k0, j1, k1, l, m, i, j, k, nh; + PICOFFTSG_FFTTYPE x; + nh = n >> 1; + x = a[1]; + a[1] = a[nh]; + a[nh] = x; + m = 2; + for (l = n >> 2; l > 2; l >>= 2) { + m <<= 1; + } + if (l == 2) { + j1 = m + 1; + k1 = m + nh; + x = a[j1]; + a[j1] = a[k1]; + a[k1] = x; + j0 = 0; + for (k0 = 2; k0 < m; k0 += 2) { + for (i = nh >> 1; i > (j0 ^= i); i >>= 1) { + /* Avoid warning*/ + } + k = k0; + for (j = j0; j < j0 + k0; j += 2) { + x = a[j]; + a[j] = a[k]; + a[k] = x; + j1 = j + m; + k1 = k + m; + x = a[j1]; + a[j1] = a[k1]; + a[k1] = x; + j1 += nh; + k1++; + x = a[j1]; + a[j1] = a[k1]; + a[k1] = x; + j1 -= m; + k1 -= m; + x = a[j1]; + a[j1] = a[k1]; + a[k1] = x; + j1++; + k1 += nh; + x = a[j1]; + a[j1] = a[k1]; + a[k1] = x; + j1 += m; + k1 += m; + x = a[j1]; + a[j1] = a[k1]; + a[k1] = x; + j1 -= nh; + k1--; + x = a[j1]; + a[j1] = a[k1]; + a[k1] = x; + j1 -= m; + k1 -= m; + x = a[j1]; + a[j1] = a[k1]; + a[k1] = x; + for (i = nh >> 1; i > (k ^= i); i >>= 1) { + /* Avoid warning*/ + } + } + k1 = j0 + k0; + j1 = k1 + 1; + k1 += nh; + x = a[j1]; + a[j1] = a[k1]; + a[k1] = x; + j1 += m; + k1 += m; + x = a[j1]; + a[j1] = a[k1]; + a[k1] = x; + } + } else { + j0 = 0; + for (k0 = 2; k0 < m; k0 += 2) { + for (i = nh >> 1; i > (j0 ^= i); i >>= 1) { + /* Avoid warning*/ + } + k = k0; + for (j = j0; j < j0 + k0; j += 2) { + x = a[j]; + a[j] = a[k]; + a[k] = x; + j1 = j + nh; + k1 = k + 1; + x = a[j1]; + a[j1] = a[k1]; + a[k1] = x; + j1++; + k1 += nh; + x = a[j1]; + a[j1] = a[k1]; + a[k1] = x; + j1 -= nh; + k1--; + x = a[j1]; + a[j1] = a[k1]; + a[k1] = x; + for (i = nh >> 1; i > (k ^= i); i >>= 1) { + /* Avoid warning*/ + } + } + k1 = j0 + k0; + j1 = k1 + 1; + k1 += nh; + x = a[j1]; + a[j1] = a[k1]; + a[k1] = x; + } + } +} + + +/* **************************************************************************************************/ + +/* **************************************************************************************************/ + +void cftb1st(picoos_int32 n, PICOFFTSG_FFTTYPE *a) +{ + picoos_int32 i, i0, j, j0, j1, j2, j3, m, mh; + PICOFFTSG_FFTTYPE wk1r, wk1i, wk3r, wk3i, + wd1r, wd1i, wd3r, wd3i, ss1, ss3; + PICOFFTSG_FFTTYPE x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + mh = n >> 3; + m = 2 * mh; + j1 = m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[0] + a[j2]; + x0i = -a[1] - a[j2 + 1]; + x1r = a[0] - a[j2]; + x1i = -a[1] + a[j2 + 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + a[0] = x0r + x2r; + a[1] = x0i - x2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i + x2i; + a[j2] = x1r + x3i; + a[j2 + 1] = x1i + x3r; + a[j3] = x1r - x3i; + a[j3 + 1] = x1i - x3r; + wd1r = PICODSP_WGT_SHIFT; + wd1i = 0; + wd3r = PICODSP_WGT_SHIFT; + wd3i = 0; + + wk1r = (PICOFFTSG_FFTTYPE) (0.998795449734 *PICODSP_WGT_SHIFT); + wk1i = (PICOFFTSG_FFTTYPE) (0.049067676067 *PICODSP_WGT_SHIFT); + ss1 = (PICOFFTSG_FFTTYPE) (0.098135352135 *PICODSP_WGT_SHIFT); + wk3i = (PICOFFTSG_FFTTYPE) (-0.146730467677 *PICODSP_WGT_SHIFT); + wk3r = (PICOFFTSG_FFTTYPE) (0.989176511765 *PICODSP_WGT_SHIFT); + ss3 = (PICOFFTSG_FFTTYPE) (-0.293460935354 *PICODSP_WGT_SHIFT); + + i = 0; + for (;;) { + i0 = i + CDFT_LOOP_DIV_4; + if (i0 > mh - 4) { + i0 = mh - 4; + } + for (j = i + 2; j < i0; j += 4) { + + wd1r -= Mult_W_W(ss1, wk1i); + wd1i += Mult_W_W(ss1, wk1r); + wd3r -= Mult_W_W(ss3, wk3i); + wd3i += Mult_W_W(ss3, wk3r); + + j1 = j + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j] + a[j2]; + x0i = -a[j + 1] - a[j2 + 1]; + x1r = a[j] - a[j2]; + x1i = -a[j + 1] + a[j2 + 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i - x2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i + x2i; + x0r = x1r + x3i; + x0i = x1i + x3r; + a[j2] = Mult_W_W(wk1r, x0r) - Mult_W_W(wk1i, x0i); + a[j2 + 1] = Mult_W_W(wk1r, x0i) + Mult_W_W(wk1i, x0r); + x0r = x1r - x3i; + x0i = x1i - x3r; + a[j3] = Mult_W_W(wk3r, x0r) + Mult_W_W(wk3i, x0i); + a[j3 + 1] = Mult_W_W(wk3r, x0i) - Mult_W_W(wk3i, x0r); + x0r = a[j + 2] + a[j2 + 2]; + x0i = -a[j + 3] - a[j2 + 3]; + x1r = a[j + 2] - a[j2 + 2]; + x1i = -a[j + 3] + a[j2 + 3]; + x2r = a[j1 + 2] + a[j3 + 2]; + x2i = a[j1 + 3] + a[j3 + 3]; + x3r = a[j1 + 2] - a[j3 + 2]; + x3i = a[j1 + 3] - a[j3 + 3]; + a[j + 2] = x0r + x2r; + a[j + 3] = x0i - x2i; + a[j1 + 2] = x0r - x2r; + a[j1 + 3] = x0i + x2i; + x0r = x1r + x3i; + x0i = x1i + x3r; + a[j2 + 2] = Mult_W_W(wd1r, x0r) - Mult_W_W(wd1i, x0i); + a[j2 + 3] = Mult_W_W(wd1r, x0i) + Mult_W_W(wd1i, x0r); + x0r = x1r - x3i; + x0i = x1i - x3r; + a[j3 + 2] = Mult_W_W(wd3r, x0r) + Mult_W_W(wd3i, x0i); + a[j3 + 3] = Mult_W_W(wd3r, x0i) - Mult_W_W(wd3i, x0r); + j0 = m - j; + j1 = j0 + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j0] + a[j2]; + x0i = -a[j0 + 1] - a[j2 + 1]; + x1r = a[j0] - a[j2]; + x1i = -a[j0 + 1] + a[j2 + 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + a[j0] = x0r + x2r; + a[j0 + 1] = x0i - x2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i + x2i; + x0r = x1r + x3i; + x0i = x1i + x3r; + a[j2] = Mult_W_W(wk1i, x0r) - Mult_W_W(wk1r, x0i); + a[j2 + 1] = Mult_W_W(wk1i, x0i) + Mult_W_W(wk1r, x0r); + x0r = x1r - x3i; + x0i = x1i - x3r; + a[j3] = Mult_W_W(wk3i, x0r) + Mult_W_W(wk3r, x0i); + a[j3 + 1] = Mult_W_W(wk3i, x0i) - Mult_W_W(wk3r, x0r); + x0r = a[j0 - 2] + a[j2 - 2]; + x0i = -a[j0 - 1] - a[j2 - 1]; + x1r = a[j0 - 2] - a[j2 - 2]; + x1i = -a[j0 - 1] + a[j2 - 1]; + x2r = a[j1 - 2] + a[j3 - 2]; + x2i = a[j1 - 1] + a[j3 - 1]; + x3r = a[j1 - 2] - a[j3 - 2]; + x3i = a[j1 - 1] - a[j3 - 1]; + a[j0 - 2] = x0r + x2r; + a[j0 - 1] = x0i - x2i; + a[j1 - 2] = x0r - x2r; + a[j1 - 1] = x0i + x2i; + x0r = x1r + x3i; + x0i = x1i + x3r; + a[j2 - 2] = Mult_W_W(wd1i, x0r) - Mult_W_W(wd1r, x0i); + a[j2 - 1] = Mult_W_W(wd1i, x0i) + Mult_W_W(wd1r, x0r); + x0r = x1r - x3i; + x0i = x1i - x3r; + a[j3 - 2] = Mult_W_W(wd3i, x0r) + Mult_W_W(wd3r, x0i); + a[j3 - 1] = Mult_W_W(wd3i, x0i) - Mult_W_W(wd3r, x0r); + wk1r -= Mult_W_W(ss1, wd1i); + wk1i += Mult_W_W(ss1, wd1r); + wk3r -= Mult_W_W(ss3, wd3i); + wk3i += Mult_W_W(ss3, wd3r); + } + if (i0 == mh - 4) { + break; + } + } + wd1r = WR5000; + j0 = mh; + j1 = j0 + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j0 - 2] + a[j2 - 2]; + x0i = -a[j0 - 1] - a[j2 - 1]; + x1r = a[j0 - 2] - a[j2 - 2]; + x1i = -a[j0 - 1] + a[j2 - 1]; + x2r = a[j1 - 2] + a[j3 - 2]; + x2i = a[j1 - 1] + a[j3 - 1]; + x3r = a[j1 - 2] - a[j3 - 2]; + x3i = a[j1 - 1] - a[j3 - 1]; + a[j0 - 2] = x0r + x2r; + a[j0 - 1] = x0i - x2i; + a[j1 - 2] = x0r - x2r; + a[j1 - 1] = x0i + x2i; + x0r = x1r + x3i; + x0i = x1i + x3r; + a[j2 - 2] = Mult_W_W(wk1r, x0r) - Mult_W_W(wk1i, x0i); + a[j2 - 1] = Mult_W_W(wk1r, x0i) + Mult_W_W(wk1i, x0r); + x0r = x1r - x3i; + x0i = x1i - x3r; + a[j3 - 2] = Mult_W_W(wk3r, x0r) + Mult_W_W(wk3i, x0i); + a[j3 - 1] = Mult_W_W(wk3r, x0i) - Mult_W_W(wk3i, x0r); + x0r = a[j0] + a[j2]; + x0i = -a[j0 + 1] - a[j2 + 1]; + x1r = a[j0] - a[j2]; + x1i = -a[j0 + 1] + a[j2 + 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + a[j0] = x0r + x2r; + a[j0 + 1] = x0i - x2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i + x2i; + x0r = x1r + x3i; + x0i = x1i + x3r; + a[j2] = picofftsg_mult_w_a(wd1r, (x0r - x0i)); + a[j2 + 1] = picofftsg_mult_w_a(wd1r, (x0i + x0r)); + x0r = x1r - x3i; + x0i = x1i - x3r; + a[j3] = -picofftsg_mult_w_a(wd1r, (x0r + x0i)); + a[j3 + 1] = -picofftsg_mult_w_a(wd1r, (x0i - x0r)); + x0r = a[j0 + 2] + a[j2 + 2]; + x0i = -a[j0 + 3] - a[j2 + 3]; + x1r = a[j0 + 2] - a[j2 + 2]; + x1i = -a[j0 + 3] + a[j2 + 3]; + x2r = a[j1 + 2] + a[j3 + 2]; + x2i = a[j1 + 3] + a[j3 + 3]; + x3r = a[j1 + 2] - a[j3 + 2]; + x3i = a[j1 + 3] - a[j3 + 3]; + a[j0 + 2] = x0r + x2r; + a[j0 + 3] = x0i - x2i; + a[j1 + 2] = x0r - x2r; + a[j1 + 3] = x0i + x2i; + x0r = x1r + x3i; + x0i = x1i + x3r; + a[j2 + 2] = Mult_W_W(wk1i, x0r) - Mult_W_W(wk1r, x0i); + a[j2 + 3] = Mult_W_W(wk1i, x0i) + Mult_W_W(wk1r, x0r); + x0r = x1r - x3i; + x0i = x1i - x3r; + a[j3 + 2] = Mult_W_W(wk3i, x0r) + Mult_W_W(wk3r, x0i); + a[j3 + 3] = Mult_W_W(wk3i, x0i) - Mult_W_W(wk3r, x0r); +} + +void cftrec4(picoos_int32 n, PICOFFTSG_FFTTYPE *a) +{ + picoos_int32 isplt, j, k, m; + + m = n; + while (m > 512) { + m >>= 2; + cftmdl1(m, &a[n - m]); + } + cftleaf(m, 1, &a[n - m]); + k = 0; + for (j = n - m; j > 0; j -= m) { + k++; + isplt = cfttree(m, j, k, a); + cftleaf(m, isplt, &a[j - m]); + } +} + + +picoos_int32 cfttree(picoos_int32 n, picoos_int32 j, picoos_int32 k, PICOFFTSG_FFTTYPE *a) +{ + picoos_int32 i, isplt, m; + + if ((k & 3) != 0) { + isplt = k & 1; + if (isplt != 0) { + cftmdl1(n, &a[j - n]); + } else { + cftmdl2(n, &a[j - n]); + } + } else { + m = n; + for (i = k; (i & 3) == 0; i >>= 2) { + m <<= 2; + } + isplt = i & 1; + if (isplt != 0) { + while (m > 128) { + cftmdl1(m, &a[j - m]); + m >>= 2; + } + } else { + while (m > 128) { + cftmdl2(m, &a[j - m]); + m >>= 2; + } + } + } + return isplt; +} + + +void cftleaf(picoos_int32 n, picoos_int32 isplt, PICOFFTSG_FFTTYPE *a) +{ + + if (n == 512) { + cftmdl1(128, a); + cftf161(a); + cftf162(&a[32]); + cftf161(&a[64]); + cftf161(&a[96]); + cftmdl2(128, &a[128]); + cftf161(&a[128]); + cftf162(&a[160]); + cftf161(&a[192]); + cftf162(&a[224]); + cftmdl1(128, &a[256]); + cftf161(&a[256]); + cftf162(&a[288]); + cftf161(&a[320]); + cftf161(&a[352]); + if (isplt != 0) { + cftmdl1(128, &a[384]); + cftf161(&a[480]); + } else { + cftmdl2(128, &a[384]); + cftf162(&a[480]); + } + cftf161(&a[384]); + cftf162(&a[416]); + cftf161(&a[448]); + } else { + cftmdl1(64, a); + cftf081(a); + cftf082(&a[16]); + cftf081(&a[32]); + cftf081(&a[48]); + cftmdl2(64, &a[64]); + cftf081(&a[64]); + cftf082(&a[80]); + cftf081(&a[96]); + cftf082(&a[112]); + cftmdl1(64, &a[128]); + cftf081(&a[128]); + cftf082(&a[144]); + cftf081(&a[160]); + cftf081(&a[176]); + if (isplt != 0) { + cftmdl1(64, &a[192]); + cftf081(&a[240]); + } else { + cftmdl2(64, &a[192]); + cftf082(&a[240]); + } + cftf081(&a[192]); + cftf082(&a[208]); + cftf081(&a[224]); + } +} + + +void cftmdl1(picoos_int32 n, PICOFFTSG_FFTTYPE *a) +{ + picoos_int32 i, i0, j, j0, j1, j2, j3, m, mh; + PICOFFTSG_FFTTYPE wk1r, wk1i, wk3r, wk3i, + wd1r, wd1i, wd3r, wd3i, ss1, ss3; + PICOFFTSG_FFTTYPE x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + mh = n >> 3; + m = 2 * mh; + j1 = m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[0] + a[j2]; + x0i = a[1] + a[j2 + 1]; + x1r = a[0] - a[j2]; + x1i = a[1] - a[j2 + 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + a[0] = x0r + x2r; + a[1] = x0i + x2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i - x2i; + a[j2] = x1r - x3i; + a[j2 + 1] = x1i + x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + wd1r = (PICOFFTSG_FFTTYPE)(PICODSP_WGT_SHIFT); + wd1i = 0; + wd3r = (PICOFFTSG_FFTTYPE)(PICODSP_WGT_SHIFT); + wd3i = 0; + wk1r = (PICOFFTSG_FFTTYPE) (0.980785250664 *PICODSP_WGT_SHIFT); + wk1i = (PICOFFTSG_FFTTYPE) (0.195090323687 *PICODSP_WGT_SHIFT); + ss1 = (PICOFFTSG_FFTTYPE) (0.390180647373 *PICODSP_WGT_SHIFT); + wk3i = (PICOFFTSG_FFTTYPE) (-0.555570185184 *PICODSP_WGT_SHIFT); + wk3r = (PICOFFTSG_FFTTYPE) (0.831469595432 *PICODSP_WGT_SHIFT); + ss3 = (PICOFFTSG_FFTTYPE) (-1.111140370369 *PICODSP_WGT_SHIFT); + + i = 0; + for (;;) { + i0 = i + CDFT_LOOP_DIV_4; + if (i0 > mh - 4) { + i0 = mh - 4; + } + for (j = i + 2; j < i0; j += 4) { + wd1r -= Mult_W_W(ss1, wk1i); + wd1i += Mult_W_W(ss1, wk1r); + wd3r -= Mult_W_W(ss3, wk3i); + wd3i += Mult_W_W(ss3, wk3r); + j1 = j + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j] + a[j2]; + x0i = a[j + 1] + a[j2 + 1]; + x1r = a[j] - a[j2]; + x1i = a[j + 1] - a[j2 + 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j2] = Mult_W_W(wk1r, x0r) - Mult_W_W(wk1i, x0i); + a[j2 + 1] = Mult_W_W(wk1r, x0i) + Mult_W_W(wk1i, x0r); + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = Mult_W_W(wk3r, x0r) + Mult_W_W(wk3i, x0i); + a[j3 + 1] = Mult_W_W(wk3r, x0i) - Mult_W_W(wk3i, x0r); + x0r = a[j + 2] + a[j2 + 2]; + x0i = a[j + 3] + a[j2 + 3]; + x1r = a[j + 2] - a[j2 + 2]; + x1i = a[j + 3] - a[j2 + 3]; + x2r = a[j1 + 2] + a[j3 + 2]; + x2i = a[j1 + 3] + a[j3 + 3]; + x3r = a[j1 + 2] - a[j3 + 2]; + x3i = a[j1 + 3] - a[j3 + 3]; + a[j + 2] = x0r + x2r; + a[j + 3] = x0i + x2i; + a[j1 + 2] = x0r - x2r; + a[j1 + 3] = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j2 + 2] = Mult_W_W(wd1r, x0r) - Mult_W_W(wd1i, x0i); + a[j2 + 3] = Mult_W_W(wd1r, x0i) + Mult_W_W(wd1i, x0r); + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3 + 2] = Mult_W_W(wd3r, x0r) + Mult_W_W(wd3i, x0i); + a[j3 + 3] = Mult_W_W(wd3r, x0i) - Mult_W_W(wd3i, x0r); + j0 = m - j; + j1 = j0 + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j0] + a[j2]; + x0i = a[j0 + 1] + a[j2 + 1]; + x1r = a[j0] - a[j2]; + x1i = a[j0 + 1] - a[j2 + 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + a[j0] = x0r + x2r; + a[j0 + 1] = x0i + x2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j2] = Mult_W_W(wk1i, x0r) - Mult_W_W(wk1r, x0i); + a[j2 + 1] = Mult_W_W(wk1i, x0i) + Mult_W_W(wk1r, x0r); + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = Mult_W_W(wk3i, x0r) + Mult_W_W(wk3r, x0i); + a[j3 + 1] = Mult_W_W(wk3i, x0i) - Mult_W_W(wk3r, x0r); + x0r = a[j0 - 2] + a[j2 - 2]; + x0i = a[j0 - 1] + a[j2 - 1]; + x1r = a[j0 - 2] - a[j2 - 2]; + x1i = a[j0 - 1] - a[j2 - 1]; + x2r = a[j1 - 2] + a[j3 - 2]; + x2i = a[j1 - 1] + a[j3 - 1]; + x3r = a[j1 - 2] - a[j3 - 2]; + x3i = a[j1 - 1] - a[j3 - 1]; + a[j0 - 2] = x0r + x2r; + a[j0 - 1] = x0i + x2i; + a[j1 - 2] = x0r - x2r; + a[j1 - 1] = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j2 - 2] = Mult_W_W(wd1i, x0r) - Mult_W_W(wd1r, x0i); + a[j2 - 1] = Mult_W_W(wd1i, x0i) + Mult_W_W(wd1r, x0r); + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3 - 2] = Mult_W_W(wd3i, x0r) + Mult_W_W(wd3r, x0i); + a[j3 - 1] = Mult_W_W(wd3i, x0i) - Mult_W_W(wd3r, x0r); + wk1r -= Mult_W_W(ss1, wd1i); + wk1i += Mult_W_W(ss1, wd1r); + wk3r -= Mult_W_W(ss3, wd3i); + wk3i += Mult_W_W(ss3, wd3r); + } + if (i0 == mh - 4) { + break; + } + } + wd1r = WR5000; + j0 = mh; + j1 = j0 + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j0 - 2] + a[j2 - 2]; + x0i = a[j0 - 1] + a[j2 - 1]; + x1r = a[j0 - 2] - a[j2 - 2]; + x1i = a[j0 - 1] - a[j2 - 1]; + x2r = a[j1 - 2] + a[j3 - 2]; + x2i = a[j1 - 1] + a[j3 - 1]; + x3r = a[j1 - 2] - a[j3 - 2]; + x3i = a[j1 - 1] - a[j3 - 1]; + a[j0 - 2] = x0r + x2r; + a[j0 - 1] = x0i + x2i; + a[j1 - 2] = x0r - x2r; + a[j1 - 1] = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j2 - 2] = Mult_W_W(wk1r, x0r) - Mult_W_W(wk1i, x0i); + a[j2 - 1] = Mult_W_W(wk1r, x0i) + Mult_W_W(wk1i, x0r); + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3 - 2] = Mult_W_W(wk3r, x0r) + Mult_W_W(wk3i, x0i); + a[j3 - 1] = Mult_W_W(wk3r, x0i) - Mult_W_W(wk3i, x0r); + x0r = a[j0] + a[j2]; + x0i = a[j0 + 1] + a[j2 + 1]; + x1r = a[j0] - a[j2]; + x1i = a[j0 + 1] - a[j2 + 1]; + x2r = a[j1] + a[j3]; + x2i = a[j1 + 1] + a[j3 + 1]; + x3r = a[j1] - a[j3]; + x3i = a[j1 + 1] - a[j3 + 1]; + a[j0] = x0r + x2r; + a[j0 + 1] = x0i + x2i; + a[j1] = x0r - x2r; + a[j1 + 1] = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j2] = picofftsg_mult_w_a(wd1r, (x0r - x0i)); + a[j2 + 1] = picofftsg_mult_w_a(wd1r, (x0i + x0r)); + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = -picofftsg_mult_w_a(wd1r, (x0r + x0i)); + a[j3 + 1] = -picofftsg_mult_w_a(wd1r, (x0i - x0r)); + x0r = a[j0 + 2] + a[j2 + 2]; + x0i = a[j0 + 3] + a[j2 + 3]; + x1r = a[j0 + 2] - a[j2 + 2]; + x1i = a[j0 + 3] - a[j2 + 3]; + x2r = a[j1 + 2] + a[j3 + 2]; + x2i = a[j1 + 3] + a[j3 + 3]; + x3r = a[j1 + 2] - a[j3 + 2]; + x3i = a[j1 + 3] - a[j3 + 3]; + a[j0 + 2] = x0r + x2r; + a[j0 + 3] = x0i + x2i; + a[j1 + 2] = x0r - x2r; + a[j1 + 3] = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j2 + 2] = Mult_W_W(wk1i, x0r) - Mult_W_W(wk1r, x0i); + a[j2 + 3] = Mult_W_W(wk1i, x0i) + Mult_W_W(wk1r, x0r); + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3 + 2] = Mult_W_W(wk3i, x0r) + Mult_W_W(wk3r, x0i); + a[j3 + 3] = Mult_W_W(wk3i, x0i) - Mult_W_W(wk3r, x0r); +} + + +void cftmdl2(picoos_int32 n, PICOFFTSG_FFTTYPE *a) +{ + picoos_int32 i, i0, j, j0, j1, j2, j3, m, mh; + PICOFFTSG_FFTTYPE wn4r, wk1r, wk1i, wk3r, wk3i, + wl1r, wl1i, wl3r, wl3i, wd1r, wd1i, wd3r, wd3i, + we1r, we1i, we3r, we3i, ss1, ss3; + PICOFFTSG_FFTTYPE x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, y0r, y0i, y2r, y2i; + + mh = n >> 3; + m = 2 * mh; + wn4r = WR5000; + j1 = m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[0] - a[j2 + 1]; + x0i = a[1] + a[j2]; + x1r = a[0] + a[j2 + 1]; + x1i = a[1] - a[j2]; + x2r = a[j1] - a[j3 + 1]; + x2i = a[j1 + 1] + a[j3]; + x3r = a[j1] + a[j3 + 1]; + x3i = a[j1 + 1] - a[j3]; + y0r = picofftsg_mult_w_a(wn4r, (x2r - x2i)); + y0i = picofftsg_mult_w_a(wn4r, (x2i + x2r)); + a[0] = x0r + y0r; + a[1] = x0i + y0i; + a[j1] = x0r - y0r; + a[j1 + 1] = x0i - y0i; + y0r = picofftsg_mult_w_a(wn4r, (x3r - x3i)); + y0i = picofftsg_mult_w_a(wn4r, (x3i + x3r)); + a[j2] = x1r - y0i; + a[j2 + 1] = x1i + y0r; + a[j3] = x1r + y0i; + a[j3 + 1] = x1i - y0r; + wl1r = PICODSP_WGT_SHIFT; + wl1i = 0; + wl3r = PICODSP_WGT_SHIFT; + wl3i = 0; + we1r = wn4r; + we1i = wn4r; + we3r = -wn4r; + we3i = -wn4r; + + wk1r = (PICOFFTSG_FFTTYPE)(0.995184719563 *PICODSP_WGT_SHIFT); + wk1i = (PICOFFTSG_FFTTYPE)(0.098017141223 *PICODSP_WGT_SHIFT); + wd1r = (PICOFFTSG_FFTTYPE)(0.634393274784 *PICODSP_WGT_SHIFT); + wd1i = (PICOFFTSG_FFTTYPE)(0.773010432720 *PICODSP_WGT_SHIFT); + ss1 = (PICOFFTSG_FFTTYPE)(0.196034282446 *PICODSP_WGT_SHIFT); + wk3i = (PICOFFTSG_FFTTYPE)(-0.290284663439 *PICODSP_WGT_SHIFT); + wk3r = (PICOFFTSG_FFTTYPE)(0.956940352917 *PICODSP_WGT_SHIFT); + ss3 = (PICOFFTSG_FFTTYPE)(-0.580569326878 *PICODSP_WGT_SHIFT); + wd3r = (PICOFFTSG_FFTTYPE)(-0.881921231747 *PICODSP_WGT_SHIFT); + wd3i = (PICOFFTSG_FFTTYPE)(-0.471396744251 *PICODSP_WGT_SHIFT); + + i = 0; + for (;;) { + i0 = i + 4 * CDFT_LOOP_DIV; + if (i0 > mh - 4) { + i0 = mh - 4; + } + for (j = i + 2; j < i0; j += 4) { + wl1r -= Mult_W_W(ss1, wk1i); + wl1i += Mult_W_W(ss1, wk1r); + wl3r -= Mult_W_W(ss3, wk3i); + wl3i += Mult_W_W(ss3, wk3r); + we1r -= Mult_W_W(ss1, wd1i); + we1i += Mult_W_W(ss1, wd1r); + we3r -= Mult_W_W(ss3, wd3i); + we3i += Mult_W_W(ss3, wd3r); + j1 = j + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j] - a[j2 + 1]; + x0i = a[j + 1] + a[j2]; + x1r = a[j] + a[j2 + 1]; + x1i = a[j + 1] - a[j2]; + x2r = a[j1] - a[j3 + 1]; + x2i = a[j1 + 1] + a[j3]; + x3r = a[j1] + a[j3 + 1]; + x3i = a[j1 + 1] - a[j3]; + y0r = Mult_W_W(wk1r, x0r) - Mult_W_W(wk1i, x0i); + y0i = Mult_W_W(wk1r, x0i) + Mult_W_W(wk1i, x0r); + y2r = Mult_W_W(wd1r, x2r) - Mult_W_W(wd1i, x2i); + y2i = Mult_W_W(wd1r, x2i) + Mult_W_W(wd1i, x2r); + a[j] = y0r + y2r; + a[j + 1] = y0i + y2i; + a[j1] = y0r - y2r; + a[j1 + 1] = y0i - y2i; + y0r = Mult_W_W(wk3r, x1r) + Mult_W_W(wk3i, x1i); + y0i = Mult_W_W(wk3r, x1i) - Mult_W_W(wk3i, x1r); + y2r = Mult_W_W(wd3r, x3r) + Mult_W_W(wd3i, x3i); + y2i = Mult_W_W(wd3r, x3i) - Mult_W_W(wd3i, x3r); + a[j2] = y0r + y2r; + a[j2 + 1] = y0i + y2i; + a[j3] = y0r - y2r; + a[j3 + 1] = y0i - y2i; + x0r = a[j + 2] - a[j2 + 3]; + x0i = a[j + 3] + a[j2 + 2]; + x1r = a[j + 2] + a[j2 + 3]; + x1i = a[j + 3] - a[j2 + 2]; + x2r = a[j1 + 2] - a[j3 + 3]; + x2i = a[j1 + 3] + a[j3 + 2]; + x3r = a[j1 + 2] + a[j3 + 3]; + x3i = a[j1 + 3] - a[j3 + 2]; + y0r = Mult_W_W(wl1r, x0r) - Mult_W_W(wl1i, x0i); + y0i = Mult_W_W(wl1r, x0i) + Mult_W_W(wl1i, x0r); + y2r = Mult_W_W(we1r, x2r) - Mult_W_W(we1i, x2i); + y2i = Mult_W_W(we1r, x2i) + Mult_W_W(we1i, x2r); + a[j + 2] = y0r + y2r; + a[j + 3] = y0i + y2i; + a[j1 + 2] = y0r - y2r; + a[j1 + 3] = y0i - y2i; + y0r = Mult_W_W(wl3r, x1r) + Mult_W_W(wl3i, x1i); + y0i = Mult_W_W(wl3r, x1i) - Mult_W_W(wl3i, x1r); + y2r = Mult_W_W(we3r, x3r) + Mult_W_W(we3i, x3i); + y2i = Mult_W_W(we3r, x3i) - Mult_W_W(we3i, x3r); + a[j2 + 2] = y0r + y2r; + a[j2 + 3] = y0i + y2i; + a[j3 + 2] = y0r - y2r; + a[j3 + 3] = y0i - y2i; + j0 = m - j; + j1 = j0 + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j0] - a[j2 + 1]; + x0i = a[j0 + 1] + a[j2]; + x1r = a[j0] + a[j2 + 1]; + x1i = a[j0 + 1] - a[j2]; + x2r = a[j1] - a[j3 + 1]; + x2i = a[j1 + 1] + a[j3]; + x3r = a[j1] + a[j3 + 1]; + x3i = a[j1 + 1] - a[j3]; + y0r = Mult_W_W(wd1i, x0r) - Mult_W_W(wd1r, x0i); + y0i = Mult_W_W(wd1i, x0i) + Mult_W_W(wd1r, x0r); + y2r = Mult_W_W(wk1i, x2r) - Mult_W_W(wk1r, x2i); + y2i = Mult_W_W(wk1i, x2i) + Mult_W_W(wk1r, x2r); + a[j0] = y0r + y2r; + a[j0 + 1] = y0i + y2i; + a[j1] = y0r - y2r; + a[j1 + 1] = y0i - y2i; + y0r = Mult_W_W(wd3i, x1r) + Mult_W_W(wd3r, x1i); + y0i = Mult_W_W(wd3i, x1i) - Mult_W_W(wd3r, x1r); + y2r = Mult_W_W(wk3i, x3r) + Mult_W_W(wk3r, x3i); + y2i = Mult_W_W(wk3i, x3i) - Mult_W_W(wk3r, x3r); + a[j2] = y0r + y2r; + a[j2 + 1] = y0i + y2i; + a[j3] = y0r - y2r; + a[j3 + 1] = y0i - y2i; + x0r = a[j0 - 2] - a[j2 - 1]; + x0i = a[j0 - 1] + a[j2 - 2]; + x1r = a[j0 - 2] + a[j2 - 1]; + x1i = a[j0 - 1] - a[j2 - 2]; + x2r = a[j1 - 2] - a[j3 - 1]; + x2i = a[j1 - 1] + a[j3 - 2]; + x3r = a[j1 - 2] + a[j3 - 1]; + x3i = a[j1 - 1] - a[j3 - 2]; + y0r = Mult_W_W(we1i, x0r) - Mult_W_W(we1r, x0i); + y0i = Mult_W_W(we1i, x0i) + Mult_W_W(we1r, x0r); + y2r = Mult_W_W(wl1i, x2r) - Mult_W_W(wl1r, x2i); + y2i = Mult_W_W(wl1i, x2i) + Mult_W_W(wl1r, x2r); + a[j0 - 2] = y0r + y2r; + a[j0 - 1] = y0i + y2i; + a[j1 - 2] = y0r - y2r; + a[j1 - 1] = y0i - y2i; + y0r = Mult_W_W(we3i, x1r) + Mult_W_W(we3r, x1i); + y0i = Mult_W_W(we3i, x1i) - Mult_W_W(we3r, x1r); + y2r = Mult_W_W(wl3i, x3r) + Mult_W_W(wl3r, x3i); + y2i = Mult_W_W(wl3i, x3i) - Mult_W_W(wl3r, x3r); + a[j2 - 2] = y0r + y2r; + a[j2 - 1] = y0i + y2i; + a[j3 - 2] = y0r - y2r; + a[j3 - 1] = y0i - y2i; + wk1r -= Mult_W_W(ss1, wl1i); + wk1i += Mult_W_W(ss1, wl1r); + wk3r -= Mult_W_W(ss3, wl3i); + wk3i += Mult_W_W(ss3, wl3r); + wd1r -= Mult_W_W(ss1, we1i); + wd1i += Mult_W_W(ss1, we1r); + wd3r -= Mult_W_W(ss3, we3i); + wd3i += Mult_W_W(ss3, we3r); + } + if (i0 == mh - 4) { + break; + } + } + wl1r = WR2500; + wl1i = WI2500; + j0 = mh; + j1 = j0 + m; + j2 = j1 + m; + j3 = j2 + m; + x0r = a[j0 - 2] - a[j2 - 1]; + x0i = a[j0 - 1] + a[j2 - 2]; + x1r = a[j0 - 2] + a[j2 - 1]; + x1i = a[j0 - 1] - a[j2 - 2]; + x2r = a[j1 - 2] - a[j3 - 1]; + x2i = a[j1 - 1] + a[j3 - 2]; + x3r = a[j1 - 2] + a[j3 - 1]; + x3i = a[j1 - 1] - a[j3 - 2]; + y0r = Mult_W_W(wk1r, x0r) - Mult_W_W(wk1i, x0i); + y0i = Mult_W_W(wk1r, x0i) + Mult_W_W(wk1i, x0r); + y2r = Mult_W_W(wd1r, x2r) - Mult_W_W(wd1i, x2i); + y2i = Mult_W_W(wd1r, x2i) + Mult_W_W(wd1i, x2r); + a[j0 - 2] = y0r + y2r; + a[j0 - 1] = y0i + y2i; + a[j1 - 2] = y0r - y2r; + a[j1 - 1] = y0i - y2i; + y0r = Mult_W_W(wk3r, x1r) + Mult_W_W(wk3i, x1i); + y0i = Mult_W_W(wk3r, x1i) - Mult_W_W(wk3i, x1r); + y2r = Mult_W_W(wd3r, x3r) + Mult_W_W(wd3i, x3i); + y2i = Mult_W_W(wd3r, x3i) - Mult_W_W(wd3i, x3r); + a[j2 - 2] = y0r + y2r; + a[j2 - 1] = y0i + y2i; + a[j3 - 2] = y0r - y2r; + a[j3 - 1] = y0i - y2i; + x0r = a[j0] - a[j2 + 1]; + x0i = a[j0 + 1] + a[j2]; + x1r = a[j0] + a[j2 + 1]; + x1i = a[j0 + 1] - a[j2]; + x2r = a[j1] - a[j3 + 1]; + x2i = a[j1 + 1] + a[j3]; + x3r = a[j1] + a[j3 + 1]; + x3i = a[j1 + 1] - a[j3]; + y0r = Mult_W_W(wl1r, x0r) - Mult_W_W(wl1i, x0i); + y0i = Mult_W_W(wl1r, x0i) + Mult_W_W(wl1i, x0r); + y2r = Mult_W_W(wl1i, x2r) - Mult_W_W(wl1r, x2i); + y2i = Mult_W_W(wl1i, x2i) + Mult_W_W(wl1r, x2r); + a[j0] = y0r + y2r; + a[j0 + 1] = y0i + y2i; + a[j1] = y0r - y2r; + a[j1 + 1] = y0i - y2i; + y0r = Mult_W_W(wl1i, x1r) - Mult_W_W(wl1r, x1i); + y0i = Mult_W_W(wl1i, x1i) + Mult_W_W(wl1r, x1r); + y2r = Mult_W_W(wl1r, x3r) - Mult_W_W(wl1i, x3i); + y2i = Mult_W_W(wl1r, x3i) + Mult_W_W(wl1i, x3r); + a[j2] = y0r - y2r; + a[j2 + 1] = y0i - y2i; + a[j3] = y0r + y2r; + a[j3 + 1] = y0i + y2i; + x0r = a[j0 + 2] - a[j2 + 3]; + x0i = a[j0 + 3] + a[j2 + 2]; + x1r = a[j0 + 2] + a[j2 + 3]; + x1i = a[j0 + 3] - a[j2 + 2]; + x2r = a[j1 + 2] - a[j3 + 3]; + x2i = a[j1 + 3] + a[j3 + 2]; + x3r = a[j1 + 2] + a[j3 + 3]; + x3i = a[j1 + 3] - a[j3 + 2]; + y0r = Mult_W_W(wd1i, x0r) - Mult_W_W(wd1r, x0i); + y0i = Mult_W_W(wd1i, x0i) + Mult_W_W(wd1r, x0r); + y2r = Mult_W_W(wk1i, x2r) - Mult_W_W(wk1r, x2i); + y2i = Mult_W_W(wk1i, x2i) + Mult_W_W(wk1r, x2r); + a[j0 + 2] = y0r + y2r; + a[j0 + 3] = y0i + y2i; + a[j1 + 2] = y0r - y2r; + a[j1 + 3] = y0i - y2i; + y0r = Mult_W_W(wd3i, x1r) + Mult_W_W(wd3r, x1i); + y0i = Mult_W_W(wd3i, x1i) - Mult_W_W(wd3r, x1r); + y2r = Mult_W_W(wk3i, x3r) + Mult_W_W(wk3r, x3i); + y2i = Mult_W_W(wk3i, x3i) - Mult_W_W(wk3r, x3r); + a[j2 + 2] = y0r + y2r; + a[j2 + 3] = y0i + y2i; + a[j3 + 2] = y0r - y2r; + a[j3 + 3] = y0i - y2i; +} + + +void cftfx41(picoos_int32 n, PICOFFTSG_FFTTYPE *a) +{ + + if (n == 128) { + cftf161(a); + cftf162(&a[32]); + cftf161(&a[64]); + cftf161(&a[96]); + } else { + cftf081(a); + cftf082(&a[16]); + cftf081(&a[32]); + cftf081(&a[48]); + } +} + + +void cftf161(PICOFFTSG_FFTTYPE *a) +{ + PICOFFTSG_FFTTYPE wn4r, wk1r, wk1i, + x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, + y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i, + y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i, + y8r, y8i, y9r, y9i, y10r, y10i, y11r, y11i, + y12r, y12i, y13r, y13i, y14r, y14i, y15r, y15i; + + wn4r = WR5000; + wk1r = WR2500; + wk1i = WI2500; + x0r = a[0] + a[16]; + x0i = a[1] + a[17]; + x1r = a[0] - a[16]; + x1i = a[1] - a[17]; + x2r = a[8] + a[24]; + x2i = a[9] + a[25]; + x3r = a[8] - a[24]; + x3i = a[9] - a[25]; + y0r = x0r + x2r; + y0i = x0i + x2i; + y4r = x0r - x2r; + y4i = x0i - x2i; + y8r = x1r - x3i; + y8i = x1i + x3r; + y12r = x1r + x3i; + y12i = x1i - x3r; + x0r = a[2] + a[18]; + x0i = a[3] + a[19]; + x1r = a[2] - a[18]; + x1i = a[3] - a[19]; + x2r = a[10] + a[26]; + x2i = a[11] + a[27]; + x3r = a[10] - a[26]; + x3i = a[11] - a[27]; + y1r = x0r + x2r; + y1i = x0i + x2i; + y5r = x0r - x2r; + y5i = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + y9r = Mult_W_W(wk1r, x0r) - Mult_W_W(wk1i, x0i); + y9i = Mult_W_W(wk1r, x0i) + Mult_W_W(wk1i, x0r); + x0r = x1r + x3i; + x0i = x1i - x3r; + y13r = Mult_W_W(wk1i, x0r) - Mult_W_W(wk1r, x0i); + y13i = Mult_W_W(wk1i, x0i) + Mult_W_W(wk1r, x0r); + x0r = a[4] + a[20]; + x0i = a[5] + a[21]; + x1r = a[4] - a[20]; + x1i = a[5] - a[21]; + x2r = a[12] + a[28]; + x2i = a[13] + a[29]; + x3r = a[12] - a[28]; + x3i = a[13] - a[29]; + y2r = x0r + x2r; + y2i = x0i + x2i; + y6r = x0r - x2r; + y6i = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + y10r = picofftsg_mult_w_a(wn4r, (x0r - x0i)); + y10i = picofftsg_mult_w_a(wn4r, (x0i + x0r)); + x0r = x1r + x3i; + x0i = x1i - x3r; + y14r = picofftsg_mult_w_a(wn4r, (x0r + x0i)); + y14i = picofftsg_mult_w_a(wn4r, (x0i - x0r)); + x0r = a[6] + a[22]; + x0i = a[7] + a[23]; + x1r = a[6] - a[22]; + x1i = a[7] - a[23]; + x2r = a[14] + a[30]; + x2i = a[15] + a[31]; + x3r = a[14] - a[30]; + x3i = a[15] - a[31]; + y3r = x0r + x2r; + y3i = x0i + x2i; + y7r = x0r - x2r; + y7i = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + y11r = Mult_W_W(wk1i, x0r) - Mult_W_W(wk1r, x0i); + y11i = Mult_W_W(wk1i, x0i) + Mult_W_W(wk1r, x0r); + x0r = x1r + x3i; + x0i = x1i - x3r; + y15r = Mult_W_W(wk1r, x0r) - Mult_W_W(wk1i, x0i); + y15i = Mult_W_W(wk1r, x0i) + Mult_W_W(wk1i, x0r); + x0r = y12r - y14r; + x0i = y12i - y14i; + x1r = y12r + y14r; + x1i = y12i + y14i; + x2r = y13r - y15r; + x2i = y13i - y15i; + x3r = y13r + y15r; + x3i = y13i + y15i; + a[24] = x0r + x2r; + a[25] = x0i + x2i; + a[26] = x0r - x2r; + a[27] = x0i - x2i; + a[28] = x1r - x3i; + a[29] = x1i + x3r; + a[30] = x1r + x3i; + a[31] = x1i - x3r; + x0r = y8r + y10r; + x0i = y8i + y10i; + x1r = y8r - y10r; + x1i = y8i - y10i; + x2r = y9r + y11r; + x2i = y9i + y11i; + x3r = y9r - y11r; + x3i = y9i - y11i; + a[16] = x0r + x2r; + a[17] = x0i + x2i; + a[18] = x0r - x2r; + a[19] = x0i - x2i; + a[20] = x1r - x3i; + a[21] = x1i + x3r; + a[22] = x1r + x3i; + a[23] = x1i - x3r; + x0r = y5r - y7i; + x0i = y5i + y7r; + x2r = picofftsg_mult_w_a(wn4r, (x0r - x0i)); + x2i = picofftsg_mult_w_a(wn4r, (x0i + x0r)); + x0r = y5r + y7i; + x0i = y5i - y7r; + x3r = picofftsg_mult_w_a(wn4r, (x0r - x0i)); + x3i = picofftsg_mult_w_a(wn4r, (x0i + x0r)); + x0r = y4r - y6i; + x0i = y4i + y6r; + x1r = y4r + y6i; + x1i = y4i - y6r; + a[8] = x0r + x2r; + a[9] = x0i + x2i; + a[10] = x0r - x2r; + a[11] = x0i - x2i; + a[12] = x1r - x3i; + a[13] = x1i + x3r; + a[14] = x1r + x3i; + a[15] = x1i - x3r; + x0r = y0r + y2r; + x0i = y0i + y2i; + x1r = y0r - y2r; + x1i = y0i - y2i; + x2r = y1r + y3r; + x2i = y1i + y3i; + x3r = y1r - y3r; + x3i = y1i - y3i; + a[0] = x0r + x2r; + a[1] = x0i + x2i; + a[2] = x0r - x2r; + a[3] = x0i - x2i; + a[4] = x1r - x3i; + a[5] = x1i + x3r; + a[6] = x1r + x3i; + a[7] = x1i - x3r; +} + + +void cftf162(PICOFFTSG_FFTTYPE *a) +{ + PICOFFTSG_FFTTYPE wn4r, wk1r, wk1i, wk2r, wk2i, wk3r, wk3i, + x0r, x0i, x1r, x1i, x2r, x2i, + y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i, + y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i, + y8r, y8i, y9r, y9i, y10r, y10i, y11r, y11i, + y12r, y12i, y13r, y13i, y14r, y14i, y15r, y15i; + + wn4r = WR5000; + wk1r = WR1250; + wk1i = WI1250; + wk2r = WR2500; + wk2i = WI2500; + wk3r = WR3750; + wk3i = WI3750; + x1r = a[0] - a[17]; + x1i = a[1] + a[16]; + x0r = a[8] - a[25]; + x0i = a[9] + a[24]; + x2r = picofftsg_mult_w_a(wn4r, (x0r - x0i)); + x2i = picofftsg_mult_w_a(wn4r, (x0i + x0r)); + y0r = x1r + x2r; + y0i = x1i + x2i; + y4r = x1r - x2r; + y4i = x1i - x2i; + x1r = a[0] + a[17]; + x1i = a[1] - a[16]; + x0r = a[8] + a[25]; + x0i = a[9] - a[24]; + x2r = picofftsg_mult_w_a(wn4r, (x0r - x0i)); + x2i = picofftsg_mult_w_a(wn4r, (x0i + x0r)); + y8r = x1r - x2i; + y8i = x1i + x2r; + y12r = x1r + x2i; + y12i = x1i - x2r; + x0r = a[2] - a[19]; + x0i = a[3] + a[18]; + x1r = Mult_W_W(wk1r, x0r) - Mult_W_W(wk1i, x0i); + x1i = Mult_W_W(wk1r, x0i) + Mult_W_W(wk1i, x0r); + x0r = a[10] - a[27]; + x0i = a[11] + a[26]; + x2r = Mult_W_W(wk3i, x0r) - Mult_W_W(wk3r, x0i); + x2i = Mult_W_W(wk3i, x0i) + Mult_W_W(wk3r, x0r); + y1r = x1r + x2r; + y1i = x1i + x2i; + y5r = x1r - x2r; + y5i = x1i - x2i; + x0r = a[2] + a[19]; + x0i = a[3] - a[18]; + x1r = Mult_W_W(wk3r, x0r) - Mult_W_W(wk3i, x0i); + x1i = Mult_W_W(wk3r, x0i) + Mult_W_W(wk3i, x0r); + x0r = a[10] + a[27]; + x0i = a[11] - a[26]; + x2r = Mult_W_W(wk1r, x0r) + Mult_W_W(wk1i, x0i); + x2i = Mult_W_W(wk1r, x0i) - Mult_W_W(wk1i, x0r); + y9r = x1r - x2r; + y9i = x1i - x2i; + y13r = x1r + x2r; + y13i = x1i + x2i; + x0r = a[4] - a[21]; + x0i = a[5] + a[20]; + x1r = Mult_W_W(wk2r, x0r) - Mult_W_W(wk2i, x0i); + x1i = Mult_W_W(wk2r, x0i) + Mult_W_W(wk2i, x0r); + x0r = a[12] - a[29]; + x0i = a[13] + a[28]; + x2r = Mult_W_W(wk2i, x0r) - Mult_W_W(wk2r, x0i); + x2i = Mult_W_W(wk2i, x0i) + Mult_W_W(wk2r, x0r); + y2r = x1r + x2r; + y2i = x1i + x2i; + y6r = x1r - x2r; + y6i = x1i - x2i; + x0r = a[4] + a[21]; + x0i = a[5] - a[20]; + x1r = Mult_W_W(wk2i, x0r) - Mult_W_W(wk2r, x0i); + x1i = Mult_W_W(wk2i, x0i) + Mult_W_W(wk2r, x0r); + x0r = a[12] + a[29]; + x0i = a[13] - a[28]; + x2r = Mult_W_W(wk2r, x0r) - Mult_W_W(wk2i, x0i); + x2i = Mult_W_W(wk2r, x0i) + Mult_W_W(wk2i, x0r); + y10r = x1r - x2r; + y10i = x1i - x2i; + y14r = x1r + x2r; + y14i = x1i + x2i; + x0r = a[6] - a[23]; + x0i = a[7] + a[22]; + x1r = Mult_W_W(wk3r, x0r) - Mult_W_W(wk3i, x0i); + x1i = Mult_W_W(wk3r, x0i) + Mult_W_W(wk3i, x0r); + x0r = a[14] - a[31]; + x0i = a[15] + a[30]; + x2r = Mult_W_W(wk1i, x0r) - Mult_W_W(wk1r, x0i); + x2i = Mult_W_W(wk1i, x0i) + Mult_W_W(wk1r, x0r); + y3r = x1r + x2r; + y3i = x1i + x2i; + y7r = x1r - x2r; + y7i = x1i - x2i; + x0r = a[6] + a[23]; + x0i = a[7] - a[22]; + x1r = Mult_W_W(wk1i, x0r) + Mult_W_W(wk1r, x0i); + x1i = Mult_W_W(wk1i, x0i) - Mult_W_W(wk1r, x0r); + x0r = a[14] + a[31]; + x0i = a[15] - a[30]; + x2r = Mult_W_W(wk3i, x0r) - Mult_W_W(wk3r, x0i); + x2i = Mult_W_W(wk3i, x0i) + Mult_W_W(wk3r, x0r); + y11r = x1r + x2r; + y11i = x1i + x2i; + y15r = x1r - x2r; + y15i = x1i - x2i; + x1r = y0r + y2r; + x1i = y0i + y2i; + x2r = y1r + y3r; + x2i = y1i + y3i; + a[0] = x1r + x2r; + a[1] = x1i + x2i; + a[2] = x1r - x2r; + a[3] = x1i - x2i; + x1r = y0r - y2r; + x1i = y0i - y2i; + x2r = y1r - y3r; + x2i = y1i - y3i; + a[4] = x1r - x2i; + a[5] = x1i + x2r; + a[6] = x1r + x2i; + a[7] = x1i - x2r; + x1r = y4r - y6i; + x1i = y4i + y6r; + x0r = y5r - y7i; + x0i = y5i + y7r; + x2r = picofftsg_mult_w_a(wn4r, (x0r - x0i)); + x2i = picofftsg_mult_w_a(wn4r, (x0i + x0r)); + a[8] = x1r + x2r; + a[9] = x1i + x2i; + a[10] = x1r - x2r; + a[11] = x1i - x2i; + x1r = y4r + y6i; + x1i = y4i - y6r; + x0r = y5r + y7i; + x0i = y5i - y7r; + x2r = picofftsg_mult_w_a(wn4r, (x0r - x0i)); + x2i = picofftsg_mult_w_a(wn4r, (x0i + x0r)); + a[12] = x1r - x2i; + a[13] = x1i + x2r; + a[14] = x1r + x2i; + a[15] = x1i - x2r; + x1r = y8r + y10r; + x1i = y8i + y10i; + x2r = y9r - y11r; + x2i = y9i - y11i; + a[16] = x1r + x2r; + a[17] = x1i + x2i; + a[18] = x1r - x2r; + a[19] = x1i - x2i; + x1r = y8r - y10r; + x1i = y8i - y10i; + x2r = y9r + y11r; + x2i = y9i + y11i; + a[20] = x1r - x2i; + a[21] = x1i + x2r; + a[22] = x1r + x2i; + a[23] = x1i - x2r; + x1r = y12r - y14i; + x1i = y12i + y14r; + x0r = y13r + y15i; + x0i = y13i - y15r; + x2r = picofftsg_mult_w_a(wn4r, (x0r - x0i)); + x2i = picofftsg_mult_w_a(wn4r, (x0i + x0r)); + a[24] = x1r + x2r; + a[25] = x1i + x2i; + a[26] = x1r - x2r; + a[27] = x1i - x2i; + x1r = y12r + y14i; + x1i = y12i - y14r; + x0r = y13r - y15i; + x0i = y13i + y15r; + x2r = picofftsg_mult_w_a(wn4r, (x0r - x0i)); + x2i = picofftsg_mult_w_a(wn4r, (x0i + x0r)); + a[28] = x1r - x2i; + a[29] = x1i + x2r; + a[30] = x1r + x2i; + a[31] = x1i - x2r; +} + + +void cftf081(PICOFFTSG_FFTTYPE *a) +{ + PICOFFTSG_FFTTYPE wn4r, x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, + y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i, + y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i; + + wn4r = WR5000; + x0r = a[0] + a[8]; + x0i = a[1] + a[9]; + x1r = a[0] - a[8]; + x1i = a[1] - a[9]; + x2r = a[4] + a[12]; + x2i = a[5] + a[13]; + x3r = a[4] - a[12]; + x3i = a[5] - a[13]; + y0r = x0r + x2r; + y0i = x0i + x2i; + y2r = x0r - x2r; + y2i = x0i - x2i; + y1r = x1r - x3i; + y1i = x1i + x3r; + y3r = x1r + x3i; + y3i = x1i - x3r; + x0r = a[2] + a[10]; + x0i = a[3] + a[11]; + x1r = a[2] - a[10]; + x1i = a[3] - a[11]; + x2r = a[6] + a[14]; + x2i = a[7] + a[15]; + x3r = a[6] - a[14]; + x3i = a[7] - a[15]; + y4r = x0r + x2r; + y4i = x0i + x2i; + y6r = x0r - x2r; + y6i = x0i - x2i; + x0r = x1r - x3i; + x0i = x1i + x3r; + x2r = x1r + x3i; + x2i = x1i - x3r; + y5r = picofftsg_mult_w_a(wn4r, (x0r - x0i)); + y5i = picofftsg_mult_w_a(wn4r, (x0r + x0i)); + y7r = picofftsg_mult_w_a(wn4r, (x2r - x2i)); + y7i = picofftsg_mult_w_a(wn4r, (x2r + x2i)); + a[8] = y1r + y5r; + a[9] = y1i + y5i; + a[10] = y1r - y5r; + a[11] = y1i - y5i; + a[12] = y3r - y7i; + a[13] = y3i + y7r; + a[14] = y3r + y7i; + a[15] = y3i - y7r; + a[0] = y0r + y4r; + a[1] = y0i + y4i; + a[2] = y0r - y4r; + a[3] = y0i - y4i; + a[4] = y2r - y6i; + a[5] = y2i + y6r; + a[6] = y2r + y6i; + a[7] = y2i - y6r; +} + + +void cftf082(PICOFFTSG_FFTTYPE *a) +{ + PICOFFTSG_FFTTYPE wn4r, wk1r, wk1i, x0r, x0i, x1r, x1i, + y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i, + y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i; + + wn4r = WR5000; + wk1r = WR2500; + wk1i = WI2500; + y0r = a[0] - a[9]; + y0i = a[1] + a[8]; + y1r = a[0] + a[9]; + y1i = a[1] - a[8]; + x0r = a[4] - a[13]; + x0i = a[5] + a[12]; + y2r = picofftsg_mult_w_a(wn4r, (x0r - x0i)); + y2i = picofftsg_mult_w_a(wn4r, (x0i + x0r)); + x0r = a[4] + a[13]; + x0i = a[5] - a[12]; + y3r = picofftsg_mult_w_a(wn4r, (x0r - x0i)); + y3i = picofftsg_mult_w_a(wn4r, (x0i + x0r)); + x0r = a[2] - a[11]; + x0i = a[3] + a[10]; + y4r = Mult_W_W(wk1r, x0r) - Mult_W_W(wk1i, x0i); + y4i = Mult_W_W(wk1r, x0i) + Mult_W_W(wk1i, x0r); + x0r = a[2] + a[11]; + x0i = a[3] - a[10]; + y5r = Mult_W_W(wk1i, x0r) - Mult_W_W(wk1r, x0i); + y5i = Mult_W_W(wk1i, x0i) + Mult_W_W(wk1r, x0r); + x0r = a[6] - a[15]; + x0i = a[7] + a[14]; + y6r = Mult_W_W(wk1i, x0r) - Mult_W_W(wk1r, x0i); + y6i = Mult_W_W(wk1i, x0i) + Mult_W_W(wk1r, x0r); + x0r = a[6] + a[15]; + x0i = a[7] - a[14]; + y7r = Mult_W_W(wk1r, x0r) - Mult_W_W(wk1i, x0i); + y7i = Mult_W_W(wk1r, x0i) + Mult_W_W(wk1i, x0r); + x0r = y0r + y2r; + x0i = y0i + y2i; + x1r = y4r + y6r; + x1i = y4i + y6i; + a[0] = x0r + x1r; + a[1] = x0i + x1i; + a[2] = x0r - x1r; + a[3] = x0i - x1i; + x0r = y0r - y2r; + x0i = y0i - y2i; + x1r = y4r - y6r; + x1i = y4i - y6i; + a[4] = x0r - x1i; + a[5] = x0i + x1r; + a[6] = x0r + x1i; + a[7] = x0i - x1r; + x0r = y1r - y3i; + x0i = y1i + y3r; + x1r = y5r - y7r; + x1i = y5i - y7i; + a[8] = x0r + x1r; + a[9] = x0i + x1i; + a[10] = x0r - x1r; + a[11] = x0i - x1i; + x0r = y1r + y3i; + x0i = y1i - y3r; + x1r = y5r + y7r; + x1i = y5i + y7i; + a[12] = x0r - x1i; + a[13] = x0i + x1r; + a[14] = x0r + x1i; + a[15] = x0i - x1r; +} + + +void cftf040(PICOFFTSG_FFTTYPE *a) +{ + PICOFFTSG_FFTTYPE x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + x0r = a[0] + a[4]; + x0i = a[1] + a[5]; + x1r = a[0] - a[4]; + x1i = a[1] - a[5]; + x2r = a[2] + a[6]; + x2i = a[3] + a[7]; + x3r = a[2] - a[6]; + x3i = a[3] - a[7]; + a[0] = x0r + x2r; + a[1] = x0i + x2i; + a[2] = x1r - x3i; + a[3] = x1i + x3r; + a[4] = x0r - x2r; + a[5] = x0i - x2i; + a[6] = x1r + x3i; + a[7] = x1i - x3r; +} + + +void cftb040(PICOFFTSG_FFTTYPE *a) +{ + PICOFFTSG_FFTTYPE x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + x0r = a[0] + a[4]; + x0i = a[1] + a[5]; + x1r = a[0] - a[4]; + x1i = a[1] - a[5]; + x2r = a[2] + a[6]; + x2i = a[3] + a[7]; + x3r = a[2] - a[6]; + x3i = a[3] - a[7]; + a[0] = x0r + x2r; + a[1] = x0i + x2i; + a[2] = x1r + x3i; + a[3] = x1i - x3r; + a[4] = x0r - x2r; + a[5] = x0i - x2i; + a[6] = x1r - x3i; + a[7] = x1i + x3r; +} + + +void cftx020(PICOFFTSG_FFTTYPE *a) +{ + PICOFFTSG_FFTTYPE x0r, x0i; + + x0r = a[0] - a[2]; + x0i = a[1] - a[3]; + a[0] += a[2]; + a[1] += a[3]; + a[2] = x0r; + a[3] = x0i; +} + + +void rftfsub(picoos_int32 n, PICOFFTSG_FFTTYPE *a) +{ + picoos_int32 i, i0, j, k; + PICOFFTSG_FFTTYPE w1r, w1i, wkr, wki, wdr, wdi, ss, xr, xi, yr, yi; + + wkr = 0; + wki = 0; + + switch (n) { + case 8 : + wdi=(PICOFFTSG_FFTTYPE)(0.353553414345*PICODSP_WGT_SHIFT); wdr=(PICOFFTSG_FFTTYPE)(0.146446630359*PICODSP_WGT_SHIFT); + w1r=(PICOFFTSG_FFTTYPE)(0.707106709480*PICODSP_WGT_SHIFT); w1i=(PICOFFTSG_FFTTYPE)(0.707106828690*PICODSP_WGT_SHIFT); + ss =(PICOFFTSG_FFTTYPE)(1.414213657379*PICODSP_WGT_SHIFT); break; + case 16 : + wdi=(PICOFFTSG_FFTTYPE)(0.191341713071*PICODSP_WGT_SHIFT); wdr=(PICOFFTSG_FFTTYPE)(0.038060232997*PICODSP_WGT_SHIFT); + w1r=(PICOFFTSG_FFTTYPE)(0.923879504204*PICODSP_WGT_SHIFT); w1i=(PICOFFTSG_FFTTYPE)(0.382683426142*PICODSP_WGT_SHIFT); + ss =(PICOFFTSG_FFTTYPE)(0.765366852283*PICODSP_WGT_SHIFT); break; + case 32 : + wdi=(PICOFFTSG_FFTTYPE)(0.097545161843*PICODSP_WGT_SHIFT); wdr=(PICOFFTSG_FFTTYPE)(0.009607359767*PICODSP_WGT_SHIFT); + w1r=(PICOFFTSG_FFTTYPE)(0.980785250664*PICODSP_WGT_SHIFT); w1i=(PICOFFTSG_FFTTYPE)(0.195090323687*PICODSP_WGT_SHIFT); + ss =(PICOFFTSG_FFTTYPE)(0.390180647373*PICODSP_WGT_SHIFT); break; + case 64 : + wdi=(PICOFFTSG_FFTTYPE)(0.049008570611*PICODSP_WGT_SHIFT); wdr=(PICOFFTSG_FFTTYPE)(0.002407636726*PICODSP_WGT_SHIFT); + w1r=(PICOFFTSG_FFTTYPE)(0.995184719563*PICODSP_WGT_SHIFT); w1i=(PICOFFTSG_FFTTYPE)(0.098017141223*PICODSP_WGT_SHIFT); + ss =(PICOFFTSG_FFTTYPE)(0.196034282446*PICODSP_WGT_SHIFT); break; + default : + wdr = 0; wdi = 0; ss = 0; + break; + } + + i = n >> 1; + for (;;) { + i0 = i - RDFT_LOOP_DIV_4; + if (i0 < 4) { + i0 = 4; + } + for (j = i - 4; j >= i0; j -= 4) { + k = n - j; + xr = a[j + 2] - a[k - 2]; + xi = a[j + 3] + a[k - 1]; + yr = Mult_W_W(wdr, xr) - Mult_W_W(wdi, xi); + yi = Mult_W_W(wdr, xi) + Mult_W_W(wdi, xr); + a[j + 2] -= yr; + a[j + 3] -= yi; + a[k - 2] += yr; + a[k - 1] -= yi; + wkr += Mult_W_W(ss, wdi); + wki += picofftsg_mult_w_w(ss, (PICOFFTSG_WGT_SHIFT2 - wdr)); + xr = a[j] - a[k]; + xi = a[j + 1] + a[k + 1]; + yr = Mult_W_W(wkr, xr) - Mult_W_W(wki, xi); + yi = Mult_W_W(wkr, xi) + Mult_W_W(wki, xr); + a[j] -= yr; + a[j + 1] -= yi; + a[k] += yr; + a[k + 1] -= yi; + wdr += Mult_W_W(ss, wki); + wdi += picofftsg_mult_w_w(ss, (PICOFFTSG_WGT_SHIFT2 - wkr)); + } + if (i0 == 4) { + break; + } + } + + xr = a[2] - a[n - 2]; + xi = a[3] + a[n - 1]; + yr = Mult_W_W(wdr, xr) - Mult_W_W(wdi, xi); + yi = Mult_W_W(wdr, xi) + Mult_W_W(wdi, xr); + + a[2] -= yr; + a[3] -= yi; + a[n - 2] += yr; + a[n - 1] -= yi; + + +} + + +void rftbsub(picoos_int32 n, PICOFFTSG_FFTTYPE *a) +{ + picoos_int32 i, i0, j, k; + PICOFFTSG_FFTTYPE w1r, w1i, wkr, wki, wdr, wdi, ss, xr, xi, yr, yi; + wkr = 0; + wki = 0; + wdi=(PICOFFTSG_FFTTYPE)(0.012270614505*PICODSP_WGT_SHIFT); + wdr=(PICOFFTSG_FFTTYPE)(0.000150590655*PICODSP_WGT_SHIFT); + w1r=(PICOFFTSG_FFTTYPE)(0.999698817730*PICODSP_WGT_SHIFT); + w1i=(PICOFFTSG_FFTTYPE)(0.024541229010*PICODSP_WGT_SHIFT); + ss=(PICOFFTSG_FFTTYPE)(0.049082458019*PICODSP_WGT_SHIFT); + + i = n >> 1; + for (;;) { + i0 = i - RDFT_LOOP_DIV4; + if (i0 < 4) { + i0 = 4; + } + for (j = i - 4; j >= i0; j -= 4) { + k = n - j; + xr = a[j + 2] - a[k - 2]; + xi = a[j + 3] + a[k - 1]; + yr = Mult_W_W(wdr, xr) + Mult_W_W(wdi, xi); + yi = Mult_W_W(wdr, xi) - Mult_W_W(wdi, xr); + a[j + 2] -= yr; + a[j + 3] -= yi; + a[k - 2] += yr; + a[k - 1] -= yi; + wkr += Mult_W_W(ss, wdi); + wki += picofftsg_mult_w_w(ss, (PICOFFTSG_WGT_SHIFT2 - wdr)); + xr = a[j] - a[k]; + xi = a[j + 1] + a[k + 1]; + yr = Mult_W_W(wkr, xr) + Mult_W_W(wki, xi); + yi = Mult_W_W(wkr, xi) - Mult_W_W(wki, xr); + a[j] -= yr; + a[j + 1] -= yi; + a[k] += yr; + a[k + 1] -= yi; + wdr += Mult_W_W(ss, wki); + wdi += picofftsg_mult_w_w(ss, (PICOFFTSG_WGT_SHIFT2 - wkr)); + } + if (i0 == 4) { + break; + } + } + xr = a[2] - a[n - 2]; + xi = a[3] + a[n - 1]; + yr = Mult_W_W(wdr, xr) + Mult_W_W(wdi, xi); + yi = Mult_W_W(wdr, xi) - Mult_W_W(wdi, xr); + a[2] -= yr; + a[3] -= yi; + a[n - 2] += yr; + a[n - 1] -= yi; +} + + +void dctsub(picoos_int32 n, PICOFFTSG_FFTTYPE *a) +{ + picoos_int32 i, i0, j, k, m; + PICOFFTSG_FFTTYPE w1r, w1i, wkr, wki, wdr, wdi, ss, xr, xi, yr, yi; + wkr = (PICOFFTSG_FFTTYPE)(0.5*PICODSP_WGT_SHIFT); + wki = (PICOFFTSG_FFTTYPE)(0.5*PICODSP_WGT_SHIFT); + + switch (n) { + case 8 : wdi=(PICOFFTSG_FFTTYPE)(0.587937772274*PICODSP_WGT_SHIFT); + wdr=(PICOFFTSG_FFTTYPE)(0.392847478390*PICODSP_WGT_SHIFT); w1r=(PICOFFTSG_FFTTYPE)(0.980785250664*PICODSP_WGT_SHIFT); + w1i=(PICOFFTSG_FFTTYPE)(0.195090323687*PICODSP_WGT_SHIFT); ss =(PICOFFTSG_FFTTYPE)(0.390180647373*PICODSP_WGT_SHIFT); break; + case 16 : wdi=(PICOFFTSG_FFTTYPE)(0.546600937843*PICODSP_WGT_SHIFT); + wdr=(PICOFFTSG_FFTTYPE)(0.448583781719*PICODSP_WGT_SHIFT); w1r=(PICOFFTSG_FFTTYPE)(0.995184719563*PICODSP_WGT_SHIFT); + w1i=(PICOFFTSG_FFTTYPE)(0.098017141223*PICODSP_WGT_SHIFT); ss =(PICOFFTSG_FFTTYPE)(0.196034282446*PICODSP_WGT_SHIFT); break; + case 32 : wdi=(PICOFFTSG_FFTTYPE)(0.523931562901*PICODSP_WGT_SHIFT); + wdr=(PICOFFTSG_FFTTYPE)(0.474863886833*PICODSP_WGT_SHIFT); w1r=(PICOFFTSG_FFTTYPE)(0.998795449734*PICODSP_WGT_SHIFT); + w1i=(PICOFFTSG_FFTTYPE)(0.049067676067*PICODSP_WGT_SHIFT); ss =(PICOFFTSG_FFTTYPE)(0.098135352135*PICODSP_WGT_SHIFT); break; + case 64 : wdi=(PICOFFTSG_FFTTYPE)(0.512120008469*PICODSP_WGT_SHIFT); + wdr=(PICOFFTSG_FFTTYPE)(0.487578809261*PICODSP_WGT_SHIFT); w1r=(PICOFFTSG_FFTTYPE)(0.999698817730*PICODSP_WGT_SHIFT); + w1i=(PICOFFTSG_FFTTYPE)(0.024541229010*PICODSP_WGT_SHIFT); ss =(PICOFFTSG_FFTTYPE)(0.049082458019*PICODSP_WGT_SHIFT); break; + default: + wdr = 0; wdi = 0; ss = 0; break; + } + + m = n >> 1; + i = 0; + for (;;) { + i0 = i + DCST_LOOP_DIV2; + if (i0 > m - 2) { + i0 = m - 2; + } + for (j = i + 2; j <= i0; j += 2) { + k = n - j; + xr = picofftsg_mult_w_a(wdi, a[j - 1]) - picofftsg_mult_w_a(wdr, a[k + 1]); + xi = picofftsg_mult_w_a(wdr, a[j - 1]) + picofftsg_mult_w_a(wdi, a[k + 1]); + wkr -= Mult_W_W(ss, wdi); + wki += Mult_W_W(ss, wdr); + yr = Mult_W_W(wki, a[j]) - Mult_W_W(wkr, a[k]); + yi = Mult_W_W(wkr, a[j]) + Mult_W_W(wki, a[k]); + wdr -= Mult_W_W(ss, wki); + wdi += Mult_W_W(ss, wkr); + a[k + 1] = xr; + a[k] = yr; + a[j - 1] = xi; + a[j] = yi; + } + if (i0 == m - 2) { + break; + } + } + xr = picofftsg_mult_w_a(wdi, a[m - 1]) - picofftsg_mult_w_a(wdr, a[m + 1]); + a[m - 1] = picofftsg_mult_w_a(wdr, a[m - 1]) + picofftsg_mult_w_a(wdi, a[m + 1]); + a[m + 1] = xr; + a[m] = Mult_W_W(WR5000, a[m]); +} + + +void dctsub4(picoos_int32 n, PICOFFTSG_FFTTYPE *a) +{ + picoos_int32 m; + PICOFFTSG_FFTTYPE wki, wdr, wdi, xr; + + wki = WR5000; + m = n >> 1; + if (m == 2) { + wdr = Mult_W_W(wki, WI2500); + wdi = Mult_W_W(wki, WR2500); + xr = Mult_W_W(wdi, a[1]) - Mult_W_W(wdr, a[3]); + a[1] = Mult_W_W(wdr, a[1]) + Mult_W_W(wdi, a[3]); + a[3] = xr; + } + a[m] = Mult_W_W(wki, a[m]); +} + +#ifdef __cplusplus +} +#endif diff --git a/pico/lib/picofftsg.h b/pico/lib/picofftsg.h new file mode 100644 index 0000000..a028e75 --- /dev/null +++ b/pico/lib/picofftsg.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picofftsg.h + * + * include file for FFT/DCT related data types, constants and functions in Pico + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * +*/ +#ifndef PICOFFTSG_H_ +#define PICOFFTSG_H_ + +#include "picoos.h" +#include "picodsp.h" + + +#ifdef __cplusplus +extern "C" { + +#endif +#if 0 +} +#endif + +#define PICOFFTSG_FFTTYPE picoos_int32 + +extern void rdft(int n, int isgn, PICOFFTSG_FFTTYPE *a); +extern void dfct(int n, float *a, int VAL_SHIFT); +extern void dfct_nmf(int n, int *a); +extern float norm_result(int m2, PICOFFTSG_FFTTYPE *tmpX, PICOFFTSG_FFTTYPE *norm_window); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pico/lib/picokdbg.c b/pico/lib/picokdbg.c new file mode 100644 index 0000000..c0336ba --- /dev/null +++ b/pico/lib/picokdbg.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picokdbg.c + * + * debug support knowledge base + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include "picoos.h" +#include "picoknow.h" +#include "picodbg.h" +#include "picokdbg.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +#if defined(PICO_DEBUG) + +/** + * @addtogroup picokdbg + + * Pico Debug Support for knowledge base \n + * + + * @b Phones + + * overview of binary file format for dbg kb: + + dbg-kb = phonesyms + + phonesyms = {PHONESYM8}=256 + + PHONESYM6: 8 bytes, symbol name (must be 0 terminated), the + corresponding ID corresponds to the offset in the + phonesyms array +*/ + +/* maximum length of phonesym string including terminating 0 */ +#define KDBG_PHONESYMLEN_MAX 8 + + +typedef struct kdbg_subobj *kdbg_SubObj; + +typedef struct kdbg_subobj { + picoos_uint8 *phonesyms; +} kdbg_subobj_t; + + +static pico_status_t kdbgInitialize(register picoknow_KnowledgeBase this, + picoos_Common common) { + kdbg_subobj_t *kdbg; + + PICODBG_DEBUG(("start")); + + if (NULL == this || NULL == this->subObj) { + PICODBG_DEBUG(("2nd check failed")); + return picoos_emRaiseException(common->em, PICO_ERR_OTHER, NULL, NULL); + } + kdbg = (kdbg_subobj_t *)this->subObj; + kdbg->phonesyms = this->base; + return PICO_OK; +} + + +static pico_status_t kdbgSubObjDeallocate(register picoknow_KnowledgeBase this, + picoos_MemoryManager mm) { + if (NULL != this) { + picoos_deallocate(mm, (void *) &this->subObj); + } + return PICO_OK; +} + + +pico_status_t picokdbg_specializeDbgKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common) { + if (NULL == this) { + PICODBG_INFO(("no debug symbols loaded")); + return PICO_OK; + } + this->subDeallocate = kdbgSubObjDeallocate; + this->subObj = picoos_allocate(common->mm, sizeof(kdbg_subobj_t)); + if (NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, + NULL, NULL); + } + return kdbgInitialize(this, common); +} + + +picokdbg_Dbg picokdbg_getDbg(picoknow_KnowledgeBase this) { + if (NULL == this) { + return NULL; + } else { + return (picokdbg_Dbg)this->subObj; + } +} + + +/* Dbg methods */ + +picoos_uint8 picokdbg_getPhoneId(const picokdbg_Dbg this, + const picoos_char *phsym) { + kdbg_subobj_t *kdbg; + picoos_uint16 i; + + if (this == NULL) + return 0; + + kdbg = (kdbg_subobj_t *)this; + /* sequential search */ + for (i = 0; i < 256; i++) { + if (!picoos_strcmp(phsym, + (picoos_char *)&(kdbg->phonesyms[i * KDBG_PHONESYMLEN_MAX]))) + return (picoos_uint8)i; + } + return 0; +} + + +picoos_char *picokdbg_getPhoneSym(const picokdbg_Dbg this, + const picoos_uint8 phid) { + kdbg_subobj_t *kdbg; + + if (this == NULL) + return NULL; + + kdbg = (kdbg_subobj_t *)this; + return (picoos_char *)&(kdbg->phonesyms[phid * KDBG_PHONESYMLEN_MAX]); +} + + + +#else + +/* To prevent warning about "translation unit is empty" when + diagnostic output is disabled. */ +static void picokdbg_dummy(void) { + picokdbg_dummy(); +} + + +#endif /* defined(PICO_DEBUG) */ + +#ifdef __cplusplus +} +#endif + + +/* end */ diff --git a/pico/lib/picokdbg.h b/pico/lib/picokdbg.h new file mode 100644 index 0000000..c17942f --- /dev/null +++ b/pico/lib/picokdbg.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picokdbg.h + * + * debug support knowledge base + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + *- 0.1, 08.05.2008, MRi - initial version + * + */ + +#ifndef PICOKDBG_H_ +#define PICOKDBG_H_ + + +#include "picoos.h" +#include "picoknow.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* ************************************************************/ +/* Dbg type and functions */ +/* ************************************************************/ + +/** + * to be used by picorsrc only + */ +pico_status_t picokdbg_specializeDbgKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common); + +typedef struct picokdbg_dbg *picokdbg_Dbg; + +/** + * return kb Phones for usage in PU + */ +picokdbg_Dbg picokdbg_getDbg(picoknow_KnowledgeBase this); + + +/* phone ID - phone symbol conversion functions */ + +/** + * return phone ID for phone symbol 'phsym' which must be 0 terminated + */ +picoos_uint8 picokdbg_getPhoneId(const picokdbg_Dbg dbg, + const picoos_char *phsym); + +/** + * return pointer to phone symbol for phone ID phid + */ +picoos_char *picokdbg_getPhoneSym(const picokdbg_Dbg dbg, + const picoos_uint8 phid); + +#ifdef __cplusplus +} +#endif + + +#endif /*PICOKDBG_H_*/ diff --git a/pico/lib/picokdt.c b/pico/lib/picokdt.c new file mode 100644 index 0000000..4b24681 --- /dev/null +++ b/pico/lib/picokdt.c @@ -0,0 +1,2642 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picokdt.c + * + * knowledge handling for decision trees + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include "picoos.h" +#include "picodbg.h" +#include "picobase.h" +#include "picoknow.h" +#include "picodata.h" +#include "picokdt.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* ************************************************************/ +/* decision tree */ +/* ************************************************************/ + +/** + * @addtogroup picokdt + * ---------------------------------------------------\n + * Pico KDT support \n + * ---------------------------------------------------\n + overview extended binary tree file: + - dt consists of optional attribute mapping tables and a non-empty + tree part + - using the attribute mapping tables an attribute value as used + throughout the TTS can be mapped to its smaller representation + used in the tree + - multi-byte values always little endian + + ------------------------------------------------------------------- + - bin-file, decision tree knowledge base in binary form + + - dt-kb = header inputmaptables outputmaptables tree + + + - header = INPMAPTABLEPOS2 OUTMAPTABLEPOS2 TREEPOS2 + + - INPMAPTABLEPOS2: two bytes, equals offest in number of bytes from + the start of kb to the start of input map tables, + may not be 0 + - OUTMAPTABLEPOS2: two bytes, equals offest in number of bytes from + the start of kb to the start of outtables, + may not be 0 + - TREEPOS2: two bytes, equals offest in number of bytes from the + start of kb to the start of the tree + + + - inputmaptables = maptables + - outputmaptables = maptables + - maptables = NRMAPTABLES1 {maptable}=NRMAPTABLES1 + - maptable = LENTABLE2 TABLETYPE1 ( bytemaptable + | wordmaptable + | graphinmaptable + | bytetovarmaptable ) + - bytemaptable (in or out, usage varies) = NRBYTES2 {BYTE1}=NRBYTES2 + - wordmaptable (in or out, usage varies) = NRWORDS2 {WORD2}=NRWORDS2 + - graphinmaptable (in only) = NRGRAPHS2 {GRAPH1:4}=NRGRAPHS2 + - bytetovarmaptable (out only) = NRINBYTES2 outvarsearchind + outvaroutputs + - outvarsearchind = {OUTVAROFFSET2}=NRINBYTES2 + - outvaroutputs = {VARVALID1:}=NRINBYTES2 + + - bytemaptable: fixed size, *Map*Fixed \n + - wordmaptable: fixed size, *Map*Fixed \n + - graphinmaptable: search value is variable size (UTF8 grapheme), \n + value to be mapped to is fixed size, one byte \n + - bytetovarmaptable: search value is fixed size, one byte, values \n + to be mapped to are of variable size (e.g. several \n + phones) \n + + - NRMAPTABLES1: one byte representing the number of map tables + - LENTABLE2: two bytes, equals offset to the next table (or next + part of kb, e.g. tree), + if LENTABLE2 = 3, and + TABLETYPE1 = EMPTY -> empty table, no mapping to be done + - TABLETYPE1: one byte, type of map table (byte, word, or graph=utf8) + - NRBYTES2: two bytes, number of bytes following in the table (one + would be okay, to simplify some implementation also set + to 2) + - BYTE1: one btye, the sequence is used to determine the values + being mapped to, starting with 0 + - NRWORDS2: two bytes, number of words (two btyes) following in the table + - WORD2: two bytes, the sequence is used to determine the values + being mapped to, starting with 0 + - NRGRAPHS2: two bytes, number of graphemes encoded in UTF8 following + in table + - GRAPH1:4: one to four bytes, UTF8 representation of a grapheme, the + sequence of graphemes is used to determine the value being + mapped to, starting with 0, the length information is + encoded in UTF8, no need for extra length info + - NRINBYTES2: two bytes, number of single byte IDs the tree can produce + - OUTVAROFFSET2: two bytes, offset from the start of the + outvaroutputs to the start of the following output + phone ID group, ie. the first outvaroffset is the + offset to the start of the second PHONEID + group. Using the previous outvaroffset (or the start + of the outvaroutputs) the start and lenth of the + PHONEID group can be determined and we can get the + sequence of output values we map the chunk value to + - VARVALID1:: one to several bytes, one byte each for an output phone ID + + - tree = treenodeinfos TREEBODYSIZE4 treebody + - treenodeinfos = NRVFIELDS1 vfields NRATTRIBUTES1 NRQFIELDS1 qfields + - vfields = {VFIELD1}=NRVFIELDS1 + - qfields = {QFIELD1}=NRATTRIBUTES1xNRQFIELDS1 + - treebody = "cf. code" + + - TREEBODYSIZE4: four bytes, size of treebody in number of bytes + - NRVFIELDS1: one byte, number of node properties in the following + vector (predefined and fixed sequence of properties) + - VFIELD1: number of bits used to represent a node property + - NRATTRIBUTES1: one byte, number of attributes (rows) in the + following matrix + - NRQFIELDS1: one byte, number (columns) of question-dependent node + properties per attribute in the following matrix + (predefined and fixed sequence of properties) + - QFIELD1: number of bits used to represent a question-dependent + property in the matrix + + + - Currently, + - NRVFIELDS1 is fixed at 2 for all trees, ie. + - vfields = 2 aVFIELD1 bVFIELD1 + - aVFIELD1: nr of bits for questions + - bVFIELD1: nr of bits for decisions + + - NRQFIELDS1 is fixed at 5 for all trees, ie. \n + - qfields = NRATTRIBUTES1 5 aQFIELD1 bQFIELD1 cQFIELD1 dQFIELD1 eQFIELD1 \n + - aQFIELD1: nr of bits for fork count \n + - bQFIELD1: nr of bits for start position for subsets \n + - cQFIELD1: nr of bits for group size \n + - dQFIELD1: nr of bits for offset to reach output \n + - eQFIELD1: nr of bits for threshold (if continuous node) \n +*/ + + +/* ************************************************************/ +/* decision tree data defines */ +/* may not be changed with current implementation */ +/* ************************************************************/ + +/* maptables fields */ +#define PICOKDT_MTSPOS_NRMAPTABLES 0 + +/* position of first byte of first maptable (for omt the only table */ +#define PICOKDT_MTPOS_START 1 + +/* maptable fields */ +#define PICOKDT_MTPOS_LENTABLE 0 +#define PICOKDT_MTPOS_TABLETYPE 2 +#define PICOKDT_MTPOS_NUMBER 3 +#define PICOKDT_MTPOS_MAPSTART 5 + +/* treenodeinfos fields */ +#define PICOKDT_NIPOS_NRVFIELDS 0 +#define PICOKDT_NIPOS_NRATTS 3 +#define PICOKDT_NIPOS_NRQFIELDS 4 + +/* fixed treenodeinfos number of fields */ +#define PICOKDT_NODEINFO_NRVFIELDS 2 +#define PICOKDT_NODEINFO_NRQFIELDS 5 + +/* fixed number of bits used */ +#define PICOKDT_NODETYPE_NRBITS 2 +#define PICOKDT_SUBSETTYPE_NRBITS 2 +#define PICOKDT_ISDECIDE_NRBITS 1 + +/* number of inpmaptables for each tree. Since we have a possibly + empty input map table for each att, currently these values must be + equal to PICOKDT_NRATT* */ +typedef enum { + PICOKDT_NRINPMT_POSP = 12, + PICOKDT_NRINPMT_POSD = 7, + PICOKDT_NRINPMT_G2P = 16, + PICOKDT_NRINPMT_PHR = 8, + PICOKDT_NRINPMT_ACC = 13, + PICOKDT_NRINPMT_PAM = 60 +} kdt_nrinpmaptables_t; + +/* number of outmaptables for each tree, at least one, possibly empty, + output map table for each tree */ +typedef enum { + PICOKDT_NROUTMT_POSP = 1, + PICOKDT_NROUTMT_POSD = 1, + PICOKDT_NROUTMT_G2P = 1, + PICOKDT_NROUTMT_PHR = 1, + PICOKDT_NROUTMT_ACC = 1, + PICOKDT_NROUTMT_PAM = 1 +} kdt_nroutmaptables_t; + +/* maptable types */ +typedef enum { + PICOKDT_MTTYPE_EMPTY = 0, + PICOKDT_MTTYPE_BYTE = 1, + PICOKDT_MTTYPE_WORD = 2, + PICOKDT_MTTYPE_GRAPH = 3, + PICOKDT_MTTYPE_BYTETOVAR = 4 +} kdt_mttype_t; + + +/* ************************************************************/ +/* decision tree types and loading */ +/* ************************************************************/ +/* object : Dt*KnowledgeBase + * shortcut : kdt* + * derived from : picoknow_KnowledgeBase + */ + +/* subobj shared by all decision trees */ +typedef struct { + picokdt_kdttype_t type; + picoos_uint8 *inpmaptable; + picoos_uint8 *outmaptable; + picoos_uint8 *tree; + picoos_uint32 beg_offset[128]; /* for efficiency */ + + /* tree-internal details for faster processing */ + picoos_uint8 *vfields; + picoos_uint8 *qfields; + picoos_uint8 nrattributes; + picoos_uint8 *treebody; + /*picoos_uint8 nrvfields;*/ /* fix PICOKDT_NODEINFO_NRVFIELDS */ + /*picoos_uint8 nrqfields;*/ /* fix PICOKDT_NODEINFO_NRQFIELDS */ + + /* direct output vector (no output mapping) */ + picoos_uint8 dset; /* TRUE if class set, FALSE otherwise */ + picoos_uint16 dclass; +} kdt_subobj_t; + +/* subobj specific for each decision tree type */ +typedef struct { + kdt_subobj_t dt; + picoos_uint16 invec[PICOKDT_NRATT_POSP]; /* input vector */ + picoos_uint8 inveclen; /* nr of ele set in invec; must be =nrattributes */ +} kdtposp_subobj_t; + +typedef struct { + kdt_subobj_t dt; + picoos_uint16 invec[PICOKDT_NRATT_POSD]; /* input vector */ + picoos_uint8 inveclen; /* nr of ele set in invec; must be =nrattributes */ +} kdtposd_subobj_t; + +typedef struct { + kdt_subobj_t dt; + picoos_uint16 invec[PICOKDT_NRATT_G2P]; /* input vector */ + picoos_uint8 inveclen; /* nr of ele set in invec; must be =nrattributes */ +} kdtg2p_subobj_t; + +typedef struct { + kdt_subobj_t dt; + picoos_uint16 invec[PICOKDT_NRATT_PHR]; /* input vector */ + picoos_uint8 inveclen; /* nr of ele set in invec; must be =nrattributes */ +} kdtphr_subobj_t; + +typedef struct { + kdt_subobj_t dt; + picoos_uint16 invec[PICOKDT_NRATT_ACC]; /* input vector */ + picoos_uint8 inveclen; /* nr of ele set in invec; must be =nrattributes */ +} kdtacc_subobj_t; + +typedef struct { + kdt_subobj_t dt; + picoos_uint16 invec[PICOKDT_NRATT_PAM]; /* input vector */ + picoos_uint8 inveclen; /* nr of ele set in invec; must be =nrattributes */ +} kdtpam_subobj_t; + + +static pico_status_t kdtDtInitialize(register picoknow_KnowledgeBase this, + picoos_Common common, + kdt_subobj_t *dtp) { + picoos_uint16 inppos; + picoos_uint16 outpos; + picoos_uint16 treepos; + picoos_uint32 curpos = 0, pos; + picoos_uint16 lentable; + picoos_uint16 i; + picoos_uint8 imtnr; + + PICODBG_DEBUG(("start")); + + /* get inmap, outmap, tree offsets */ + if ((PICO_OK == picoos_read_mem_pi_uint16(this->base, &curpos, &inppos)) + && (PICO_OK == picoos_read_mem_pi_uint16(this->base, &curpos, &outpos)) + && (PICO_OK == picoos_read_mem_pi_uint16(this->base, &curpos, + &treepos))) { + + /* all pos are mandatory, verify */ + if (inppos && outpos && treepos) { + dtp->inpmaptable = this->base + inppos; + dtp->outmaptable = this->base + outpos; + dtp->tree = this->base + treepos; + /* precalc beg offset table */ + imtnr=dtp->inpmaptable[0]; + pos=1; + dtp->beg_offset[0] = 1; + for (i = 0; i < imtnr; i++) { + lentable = ((picoos_uint16)(dtp->inpmaptable[pos+1])) << 8 | + dtp->inpmaptable[pos]; + pos += lentable; + dtp->beg_offset[i+1] = pos; + } + } else { + dtp->inpmaptable = NULL; + dtp->outmaptable = NULL; + dtp->tree = NULL; + PICODBG_ERROR(("invalid kb position info")); + return picoos_emRaiseException(common->em, PICO_EXC_FILE_CORRUPT, + NULL, NULL); + } + + /* nr of outmaptables is equal 1 for all trees, verify */ + if (dtp->outmaptable[PICOKDT_MTSPOS_NRMAPTABLES] != 1) { + PICODBG_ERROR(("wrong number of outmaptables")); + return picoos_emRaiseException(common->em, PICO_EXC_FILE_CORRUPT, + NULL, NULL); + } + + /* check if this is an empty table, ie. len == 3 */ + if ((dtp->outmaptable[PICOKDT_MTPOS_START + PICOKDT_MTPOS_LENTABLE] + == 3) + && (dtp->outmaptable[PICOKDT_MTPOS_START + PICOKDT_MTPOS_LENTABLE + + 1] == 0)) { + /* verify that this is supposed to be an empty table and + set outmaptable to NULL if so */ + if (dtp->outmaptable[PICOKDT_MTPOS_START + PICOKDT_MTPOS_TABLETYPE] + == PICOKDT_MTTYPE_EMPTY) { + dtp->outmaptable = NULL; + } else { + PICODBG_ERROR(("table length vs. type problem")); + return picoos_emRaiseException(common->em, + PICO_EXC_FILE_CORRUPT, + NULL, NULL); + } + } + + dtp->vfields = dtp->tree + 1; + dtp->qfields = dtp->tree + PICOKDT_NODEINFO_NRVFIELDS + 3; + dtp->nrattributes = dtp->tree[PICOKDT_NIPOS_NRATTS]; + dtp->treebody = dtp->qfields + 4 + + (dtp->nrattributes * PICOKDT_NODEINFO_NRQFIELDS); /* TREEBODYSIZE4*/ + + /*dtp->nrvfields = dtp->tree[PICOKDT_NIPOS_NRVFIELDS]; <- is fix */ + /*dtp->nrqfields = dtp->tree[PICOKDT_NIPOS_NRQFIELDS]; <- is fix */ + /* verify that nrvfields ad nrqfields are correct */ + if ((PICOKDT_NODEINFO_NRVFIELDS != dtp->tree[PICOKDT_NIPOS_NRVFIELDS]) || + (PICOKDT_NODEINFO_NRQFIELDS != dtp->tree[PICOKDT_NIPOS_NRQFIELDS])) { + PICODBG_ERROR(("problem with nr of vfields (%d) or qfields (%d)", + dtp->tree[PICOKDT_NIPOS_NRVFIELDS], + dtp->tree[PICOKDT_NIPOS_NRQFIELDS])); + return picoos_emRaiseException(common->em, PICO_EXC_FILE_CORRUPT, + NULL, NULL); + } + dtp->dset = 0; + dtp->dclass = 0; + PICODBG_DEBUG(("tree init: nratt: %d, posomt: %d, postree: %d", + dtp->nrattributes, (dtp->outmaptable - dtp->inpmaptable), + (dtp->tree - dtp->inpmaptable))); + return PICO_OK; + } else { + PICODBG_ERROR(("problem reading kb in memory")); + return picoos_emRaiseException(common->em, PICO_EXC_FILE_CORRUPT, + NULL, NULL); + } +} + + +static pico_status_t kdtDtCheck(register picoknow_KnowledgeBase this, + picoos_Common common, + kdt_subobj_t *dtp, + kdt_nratt_t nratt, + kdt_nrinpmaptables_t nrinpmt, + kdt_nroutmaptables_t nroutmt, + kdt_mttype_t mttype) { + /* check nr attributes */ + /* check nr inpmaptables */ + /* check nr outmaptables */ + /* check outmaptable is word type */ + if ((nratt != dtp->nrattributes) + || (dtp->inpmaptable == NULL) + || (dtp->outmaptable == NULL) + || (dtp->inpmaptable[PICOKDT_MTSPOS_NRMAPTABLES] != nrinpmt) + || (dtp->outmaptable[PICOKDT_MTSPOS_NRMAPTABLES] != nroutmt) + || (dtp->outmaptable[PICOKDT_MTPOS_START+PICOKDT_MTPOS_TABLETYPE] + != mttype)) { + PICODBG_ERROR(("check failed, nratt %d, nrimt %d, nromt %d, omttype %d", + dtp->nrattributes, + dtp->inpmaptable[PICOKDT_MTSPOS_NRMAPTABLES], + dtp->outmaptable[PICOKDT_MTSPOS_NRMAPTABLES], + dtp->outmaptable[PICOKDT_MTPOS_START + + PICOKDT_MTPOS_TABLETYPE])); + return picoos_emRaiseException(common->em, PICO_EXC_FILE_CORRUPT, + NULL, NULL); + } + return PICO_OK; +} + + + +static pico_status_t kdtPosPInitialize(register picoknow_KnowledgeBase this, + picoos_Common common) { + pico_status_t status; + kdtposp_subobj_t *dtposp; + kdt_subobj_t *dt; + picoos_uint8 i; + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + dtposp = (kdtposp_subobj_t *)this->subObj; + dt = &(dtposp->dt); + dt->type = PICOKDT_KDTTYPE_POSP; + if ((status = kdtDtInitialize(this, common, dt)) != PICO_OK) { + return status; + } + if ((status = kdtDtCheck(this, common, dt, PICOKDT_NRATT_POSP, + PICOKDT_NRINPMT_POSP, PICOKDT_NROUTMT_POSP, + PICOKDT_MTTYPE_WORD)) != PICO_OK) { + return status; + } + + /* init specialized subobj part */ + for (i = 0; i < PICOKDT_NRATT_POSP; i++) { + dtposp->invec[i] = 0; + } + dtposp->inveclen = 0; + PICODBG_DEBUG(("posp tree initialized")); + return PICO_OK; +} + + +static pico_status_t kdtPosDInitialize(register picoknow_KnowledgeBase this, + picoos_Common common) { + pico_status_t status; + kdtposd_subobj_t *dtposd; + kdt_subobj_t *dt; + picoos_uint8 i; + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + dtposd = (kdtposd_subobj_t *)this->subObj; + dt = &(dtposd->dt); + dt->type = PICOKDT_KDTTYPE_POSD; + if ((status = kdtDtInitialize(this, common, dt)) != PICO_OK) { + return status; + } + if ((status = kdtDtCheck(this, common, dt, PICOKDT_NRATT_POSD, + PICOKDT_NRINPMT_POSD, PICOKDT_NROUTMT_POSD, + PICOKDT_MTTYPE_WORD)) != PICO_OK) { + return status; + } + + /* init spezialized subobj part */ + for (i = 0; i < PICOKDT_NRATT_POSD; i++) { + dtposd->invec[i] = 0; + } + dtposd->inveclen = 0; + PICODBG_DEBUG(("posd tree initialized")); + return PICO_OK; +} + + +static pico_status_t kdtG2PInitialize(register picoknow_KnowledgeBase this, + picoos_Common common) { + pico_status_t status; + kdtg2p_subobj_t *dtg2p; + kdt_subobj_t *dt; + picoos_uint8 i; + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + dtg2p = (kdtg2p_subobj_t *)this->subObj; + dt = &(dtg2p->dt); + dt->type = PICOKDT_KDTTYPE_G2P; + if ((status = kdtDtInitialize(this, common, dt)) != PICO_OK) { + return status; + } + + if ((status = kdtDtCheck(this, common, dt, PICOKDT_NRATT_G2P, + PICOKDT_NRINPMT_G2P, PICOKDT_NROUTMT_G2P, + PICOKDT_MTTYPE_BYTETOVAR)) != PICO_OK) { + return status; + } + + /* init spezialized subobj part */ + for (i = 0; i < PICOKDT_NRATT_G2P; i++) { + dtg2p->invec[i] = 0; + } + dtg2p->inveclen = 0; + PICODBG_DEBUG(("g2p tree initialized")); + return PICO_OK; +} + + +static pico_status_t kdtPhrInitialize(register picoknow_KnowledgeBase this, + picoos_Common common) { + pico_status_t status; + kdtphr_subobj_t *dtphr; + kdt_subobj_t *dt; + picoos_uint8 i; + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + dtphr = (kdtphr_subobj_t *)this->subObj; + dt = &(dtphr->dt); + dt->type = PICOKDT_KDTTYPE_PHR; + if ((status = kdtDtInitialize(this, common,dt)) != PICO_OK) { + return status; + } + + if ((status = kdtDtCheck(this, common, dt, PICOKDT_NRATT_PHR, + PICOKDT_NRINPMT_PHR, PICOKDT_NROUTMT_PHR, + PICOKDT_MTTYPE_WORD)) != PICO_OK) { + return status; + } + + /* init spezialized subobj part */ + for (i = 0; i < PICOKDT_NRATT_PHR; i++) { + dtphr->invec[i] = 0; + } + dtphr->inveclen = 0; + PICODBG_DEBUG(("phr tree initialized")); + return PICO_OK; +} + + +static pico_status_t kdtAccInitialize(register picoknow_KnowledgeBase this, + picoos_Common common) { + pico_status_t status; + kdtacc_subobj_t *dtacc; + kdt_subobj_t *dt; + picoos_uint8 i; + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + dtacc = (kdtacc_subobj_t *)this->subObj; + dt = &(dtacc->dt); + dt->type = PICOKDT_KDTTYPE_ACC; + if ((status = kdtDtInitialize(this, common, dt)) != PICO_OK) { + return status; + } + + if ((status = kdtDtCheck(this, common, dt, PICOKDT_NRATT_ACC, + PICOKDT_NRINPMT_ACC, PICOKDT_NROUTMT_ACC, + PICOKDT_MTTYPE_WORD)) != PICO_OK) { + return status; + } + + /* init spezialized subobj part */ + for (i = 0; i < PICOKDT_NRATT_ACC; i++) { + dtacc->invec[i] = 0; + } + dtacc->inveclen = 0; + PICODBG_DEBUG(("acc tree initialized")); + return PICO_OK; +} + + +static pico_status_t kdtPamInitialize(register picoknow_KnowledgeBase this, + picoos_Common common) { + pico_status_t status; + kdtpam_subobj_t *dtpam; + kdt_subobj_t *dt; + picoos_uint8 i; + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + dtpam = (kdtpam_subobj_t *)this->subObj; + dt = &(dtpam->dt); + dt->type = PICOKDT_KDTTYPE_PAM; + if ((status = kdtDtInitialize(this, common, dt)) != PICO_OK) { + return status; + } + + if ((status = kdtDtCheck(this, common, dt, PICOKDT_NRATT_PAM, + PICOKDT_NRINPMT_PAM, PICOKDT_NROUTMT_PAM, + PICOKDT_MTTYPE_WORD)) != PICO_OK) { + return status; + } + + /* init spezialized subobj part */ + for (i = 0; i < PICOKDT_NRATT_PAM; i++) { + dtpam->invec[i] = 0; + } + dtpam->inveclen = 0; + PICODBG_DEBUG(("pam tree initialized")); + return PICO_OK; +} + + +static pico_status_t kdtSubObjDeallocate(register picoknow_KnowledgeBase this, + picoos_MemoryManager mm) { + if (NULL != this) { + picoos_deallocate(mm, (void *) &this->subObj); + } + return PICO_OK; +} + + +/* we don't offer a specialized constructor for a *KnowledgeBase but + * instead a "specializer" of an allready existing generic + * picoknow_KnowledgeBase */ + +pico_status_t picokdt_specializeDtKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common, + const picokdt_kdttype_t kdttype) { + pico_status_t status; + + if (NULL == this) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + this->subDeallocate = kdtSubObjDeallocate; + switch (kdttype) { + case PICOKDT_KDTTYPE_POSP: + this->subObj = picoos_allocate(common->mm,sizeof(kdtposp_subobj_t)); + if (NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, + NULL, NULL); + } + status = kdtPosPInitialize(this, common); + break; + case PICOKDT_KDTTYPE_POSD: + this->subObj = picoos_allocate(common->mm,sizeof(kdtposd_subobj_t)); + if (NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, + NULL, NULL); + } + status = kdtPosDInitialize(this, common); + break; + case PICOKDT_KDTTYPE_G2P: + this->subObj = picoos_allocate(common->mm,sizeof(kdtg2p_subobj_t)); + if (NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, + NULL, NULL); + } + status = kdtG2PInitialize(this, common); + break; + case PICOKDT_KDTTYPE_PHR: + this->subObj = picoos_allocate(common->mm,sizeof(kdtphr_subobj_t)); + if (NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, + NULL, NULL); + } + status = kdtPhrInitialize(this, common); + break; + case PICOKDT_KDTTYPE_ACC: + this->subObj = picoos_allocate(common->mm,sizeof(kdtacc_subobj_t)); + if (NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, + NULL, NULL); + } + status = kdtAccInitialize(this, common); + break; + case PICOKDT_KDTTYPE_PAM: + this->subObj = picoos_allocate(common->mm,sizeof(kdtpam_subobj_t)); + if (NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, + NULL, NULL); + } + status = kdtPamInitialize(this, common); + break; + default: + return picoos_emRaiseException(common->em, PICO_ERR_OTHER, + NULL, NULL); + } + + if (status != PICO_OK) { + picoos_deallocate(common->mm, (void *) &this->subObj); + return picoos_emRaiseException(common->em, status, NULL, NULL); + } + return PICO_OK; +} + + +/* ************************************************************/ +/* decision tree getDt* */ +/* ************************************************************/ + +picokdt_DtPosP picokdt_getDtPosP(picoknow_KnowledgeBase this) { + return ((NULL == this) ? NULL : ((picokdt_DtPosP) this->subObj)); +} + +picokdt_DtPosD picokdt_getDtPosD(picoknow_KnowledgeBase this) { + return ((NULL == this) ? NULL : ((picokdt_DtPosD) this->subObj)); +} + +picokdt_DtG2P picokdt_getDtG2P (picoknow_KnowledgeBase this) { + return ((NULL == this) ? NULL : ((picokdt_DtG2P) this->subObj)); +} + +picokdt_DtPHR picokdt_getDtPHR (picoknow_KnowledgeBase this) { + return ((NULL == this) ? NULL : ((picokdt_DtPHR) this->subObj)); +} + +picokdt_DtACC picokdt_getDtACC (picoknow_KnowledgeBase this) { + return ((NULL == this) ? NULL : ((picokdt_DtACC) this->subObj)); +} + +picokdt_DtPAM picokdt_getDtPAM (picoknow_KnowledgeBase this) { + return ((NULL == this) ? NULL : ((picokdt_DtPAM) this->subObj)); +} + + + +/* ************************************************************/ +/* decision tree support functions, tree */ +/* ************************************************************/ + + +typedef enum { + eQuestion = 0, /* index to #bits to identify question */ + eDecide = 1 /* index to #bits to identify decision */ +} kdt_vfields_ind_t; + +typedef enum { + eForkCount = 0, /* index to #bits for number of forks */ + eBitNo = 1, /* index to #bits for index of 1st element */ + eBitCount = 2, /* index to #bits for size of the group */ + eJump = 3, /* index to #bits for offset to reach output node */ + eCut = 4 /* for contin. node: #bits for threshold checked */ +} kdt_qfields_ind_t; + +typedef enum { + eNTerminal = 0, + eNBinary = 1, + eNContinuous = 2, + eNDiscrete = 3 +} kdt_nodetypes_t; + +typedef enum { + eOneValue = 0, + eTwoValues = 1, + eWithoutBitMask = 2, + eBitMask = 3 +} kdt_subsettypes_t; + + +/* Name : kdt_jump + Function: maps the iJump offset to byte + bit coordinates + Input : iJump absolute bit offset (0..(nr-bytes-treebody)*8) + Output : iByteNo the first byte containing the bits to extract + (0..(nr-bytes-treebody)) + iBitNo the first bit to be extracted (0..7) + Returns : void + Notes : updates the iByteNo + iBitNo fields +*/ +static void kdt_jump(const picoos_uint32 iJump, + picoos_uint32 *iByteNo, + picoos_int8 *iBitNo) { + picoos_uint32 iByteSize; + + iByteSize = (iJump / 8 ); + *iBitNo = (iJump - (iByteSize * 8)) + (7 - *iBitNo); + *iByteNo += iByteSize; + if (*iBitNo >= 8) { + (*iByteNo)++; + *iBitNo = 15 - *iBitNo; + } else { + *iBitNo = 7 - *iBitNo; + } +} + + +/* replaced inline for speedup */ +/* Name : kdtIsVal + Function: Returns the binary value of the bit pointed to by iByteNo, iBitNo + Input : iByteNo ofsset to the byte containing the bits to extract + (0..sizeof(treebody)) + iBitNo ofsset to the first bit to be extracted (0..7) + Returns : 0/1 depending on the bit pointed to +*/ +/* +static picoos_uint8 kdtIsVal(register kdt_subobj_t *this, + picoos_uint32 iByteNo, + picoos_int8 iBitNo) { + return ((this->treebody[iByteNo] & ((1)< 0); +} +*/ + + +/* @todo : consider replacing inline for speedup */ + +/* Name : kdtGetQFieldsVal (was: m_QuestDependentFields) + Function: gets a byte from qfields + Input : this handle to a dt subobj + attind index of the attribute + qind index of the byte to be read + Returns : the requested byte + Notes : check that attind < this->nrattributes needed before calling + this function! +*/ +static picoos_uint8 kdtGetQFieldsVal(register kdt_subobj_t *this, + const picoos_uint8 attind, + const kdt_qfields_ind_t qind) { + /* check of qind done in initialize and (for some compilers) with typing */ + /* check of attind needed before calling this function */ + return this->qfields[(attind * PICOKDT_NODEINFO_NRQFIELDS) + qind]; +} + + +/* Name : kdtGetShiftVal (was: get_shift_value) + Function: returns the (treebody) value pointed to by iByteNo, iBitNo, + and with size iSize + Input : this reference to the processing unit struct + iSize number of bits to be extracted (0..N) + iByteNo ofsset to the byte containing the bits to extract + (0..sizeof(treebody)) + iBitNo ofsset to the first bit to be extracted (0..7) + Returns : the value requested (if size==0 --> 0 is returned) +*/ +/* +static picoos_uint32 orig_kdtGetShiftVal(register kdt_subobj_t *this, + const picoos_int16 iSize, + picoos_uint32 *iByteNo, + picoos_int8 *iBitNo) { + picoos_uint32 iVal; + picoos_int16 i; + + iVal = 0; + for (i = iSize-1; i >= 0; i--) { + if ( (this->treebody[*iByteNo] & ((1)<<(*iBitNo))) > 0) { + iVal |= ( (1) << i ); + } + (*iBitNo)--; + if (*iBitNo < 0) { + *iBitNo = 7; + (*iByteNo)++; + } + } + return iVal; +} +*/ +/* refactor */ +static picoos_uint32 kdtGetShiftVal(register kdt_subobj_t *this, + const picoos_int16 iSize, picoos_uint32 *iByteNo, picoos_int8 *iBitNo) +{ + picoos_uint32 v, b, iVal; + picoos_int16 i, j, len; + picoos_uint8 val; + + if (iSize < 4) { + iVal = 0; + for (i = iSize - 1; i >= 0; i--) { + /* no check that *iByteNo is within valid treebody range */ + if ((this->treebody[*iByteNo] & ((1) << (*iBitNo))) > 0) { + iVal |= ((1) << i); + } + (*iBitNo)--; + if (*iBitNo < 0) { + *iBitNo = 7; + (*iByteNo)++; + } + } + return iVal; + } + + b = *iByteNo; + j = *iBitNo; + len = iSize; + *iBitNo = j - iSize; + v = 0; + while (*iBitNo < 0) { + *iBitNo += 8; + (*iByteNo)++; + } + + val = this->treebody[b++]; + if (j < 7) { + switch (j) { + case 0: + val &= 0x01; + break; + case 1: + val &= 0x03; + break; + case 2: + val &= 0x07; + break; + case 3: + val &= 0x0f; + break; + case 4: + val &= 0x1f; + break; + case 5: + val &= 0x3f; + break; + case 6: + val &= 0x7f; + break; + } + } + len -= j + 1; + if (len < 0) { + val >>= -len; + } + v = val; + while (len > 0) { + if (len >= 8) { + j = 8; + } else { + j = len; + } + v <<= j; + val = this->treebody[b++]; + if (j < 8) { + switch (j) { + case 1: + val &= 0x80; + val >>= 7; + break; + case 2: + val &= 0xc0; + val >>= 6; + break; + case 3: + val &= 0xe0; + val >>= 5; + break; + case 4: + val &= 0xf0; + val >>= 4; + break; + case 5: + val &= 0xf8; + val >>= 3; + break; + case 6: + val &= 0xfc; + val >>= 2; + break; + case 7: + val &= 0xfe; + val >>= 1; + break; + } + } + v |= val; + len -= j; + } + return v; +} + + +/* Name : kdtAskTree + Function: Tree Traversal routine + Input : iByteNo ofsset to the first byte containing the bits + to extract (0..sizeof(treebody)) + iBitNo ofsset to the first bit to be extracted (0..7) + Returns : >0 continue, no solution yet found + =0 solution found + <0 error, no solution found + Notes : +*/ +static picoos_int8 kdtAskTree(register kdt_subobj_t *this, + picoos_uint16 *invec, + const kdt_nratt_t invecmax, + picoos_uint32 *iByteNo, + picoos_int8 *iBitNo) { + picoos_uint32 iNodeType; + picoos_uint8 iQuestion; + picoos_int32 iVal; + picoos_int32 iForks; + picoos_int32 iID; + + picoos_int32 iCut, iSubsetType, iBitPos, iBitCount, iPos, iJump, iDecision; + picoos_int32 i; + picoos_char iIsDecide; + + PICODBG_TRACE(("start")); + + /* get node type, value should be in kdt_nodetype_t range */ + iNodeType = kdtGetShiftVal(this, PICOKDT_NODETYPE_NRBITS, iByteNo, iBitNo); + PICODBG_TRACE(("iNodeType: %d", iNodeType)); + + /* get attribute to be used in question, check if in range, and get val */ + /* check of vfields argument done in initialize */ + iQuestion = kdtGetShiftVal(this, this->vfields[eQuestion], iByteNo, iBitNo); + if ((iQuestion < this->nrattributes) && (iQuestion < invecmax)) { + iVal = invec[iQuestion]; + } else { + this->dset = FALSE; + PICODBG_TRACE(("invalid question")); + return -1; /* iQuestion invalid */ + } + iForks = 0; + iID = -1; + PICODBG_TRACE(("iQuestion: %d", iQuestion)); + + switch (iNodeType) { + case eNBinary: { + iForks = 2; + iID = iVal; + break; + } + case eNContinuous: { + iForks = 2; + iID = 1; + iCut = kdtGetShiftVal(this, kdtGetQFieldsVal(this, iQuestion, eCut), + iByteNo, iBitNo); /*read the threshold*/ + if (iVal <= iCut) { + iID = 0; + } + break; + } + case eNDiscrete: { + iForks = + kdtGetShiftVal(this, + kdtGetQFieldsVal(this, iQuestion, eForkCount), + iByteNo, iBitNo); + + for (i = 0; i < iForks-1; i++) { + iSubsetType = + kdtGetShiftVal(this, PICOKDT_SUBSETTYPE_NRBITS, + iByteNo, iBitNo); + + switch (iSubsetType) { + case eOneValue: { + if (iID > -1) { + kdt_jump(kdtGetQFieldsVal(this, iQuestion, eBitNo), + iByteNo, iBitNo); + break; + } + iBitPos = + kdtGetShiftVal(this, + kdtGetQFieldsVal(this, iQuestion, + eBitNo), + iByteNo, iBitNo); + if (iVal == iBitPos) { + iID = i; + } + break; + } + case eTwoValues: { + if (iID > -1) { + kdt_jump((kdtGetQFieldsVal(this, iQuestion, eBitNo) + + kdtGetQFieldsVal(this, iQuestion, eBitCount)), + iByteNo, iBitNo); + break; + } + + iBitPos = + kdtGetShiftVal(this, kdtGetQFieldsVal(this, iQuestion, + eBitNo), + iByteNo, iBitNo); + iBitCount = + kdtGetShiftVal(this, kdtGetQFieldsVal(this, iQuestion, + eBitCount), + iByteNo, iBitNo); + if ((iVal == iBitPos) || (iVal == iBitCount)) { + iID = i; + } + break; + } + case eWithoutBitMask: { + if (iID > -1) { + kdt_jump((kdtGetQFieldsVal(this, iQuestion, eBitNo) + + kdtGetQFieldsVal(this, iQuestion, eBitCount)), + iByteNo, iBitNo); + break; + } + + iBitPos = + kdtGetShiftVal(this, kdtGetQFieldsVal(this, iQuestion, + eBitNo), + iByteNo, iBitNo); + iBitCount = + kdtGetShiftVal(this, kdtGetQFieldsVal(this, iQuestion, + eBitCount), + iByteNo, iBitNo); + if ((iVal >= iBitPos) && (iVal < (iBitPos + iBitCount))) { + iID = i; + } + break; + } + case eBitMask: { + iBitPos = 0; + if (iID > -1) { + kdt_jump(kdtGetQFieldsVal(this, iQuestion, eBitNo), + iByteNo, iBitNo); + } else { + iBitPos = + kdtGetShiftVal(this, + kdtGetQFieldsVal(this, iQuestion, + eBitNo), + iByteNo, iBitNo); + } + + iBitCount = + kdtGetShiftVal(this, + kdtGetQFieldsVal(this, iQuestion, + eBitCount), + iByteNo, iBitNo); + if (iID > -1) { + kdt_jump(iBitCount, iByteNo, iBitNo); + break; + } + + if ((iVal >= iBitPos) && (iVal < (iBitPos + iBitCount))) { + iPos = iVal - iBitPos; + kdt_jump((iVal - iBitPos), iByteNo, iBitNo); + /* if (kdtIsVal(this, *iByteNo, *iBitNo))*/ + if ((this->treebody[*iByteNo] & ((1)<<(*iBitNo))) > 0) { + iID = i; + } + kdt_jump((iBitCount - (iVal-iBitPos)), iByteNo, iBitNo); + } else { + kdt_jump(iBitCount, iByteNo, iBitNo); + } + break; + }/*end case eBitMask*/ + }/*end switch (iSubsetType)*/ + }/*end for ( i = 0; i < iForks-1; i++ ) */ + + /*default tree branch*/ + if (-1 == iID) { + iID = iForks-1; + } + break; + }/*end case eNDiscrete*/ + }/*end switch (iNodeType)*/ + + for (i = 0; i < iForks; i++) { + iIsDecide = kdtGetShiftVal(this, PICOKDT_ISDECIDE_NRBITS, iByteNo, iBitNo); + + PICODBG_TRACE(("doing forks: %d", i)); + + if (!iIsDecide) { + if (iID == i) { + iJump = + kdtGetShiftVal(this, kdtGetQFieldsVal(this, iQuestion, eJump), + iByteNo, iBitNo); + kdt_jump(iJump, iByteNo, iBitNo); + this->dset = FALSE; + return 1; /* to be continued, no solution yet found */ + } else { + kdt_jump(kdtGetQFieldsVal(this, iQuestion, eJump), + iByteNo, iBitNo); + } + } else { + if (iID == i) { + /* check of vfields argument done in initialize */ + iDecision = kdtGetShiftVal(this, this->vfields[eDecide], + iByteNo, iBitNo); + this->dclass = iDecision; + this->dset = TRUE; + return 0; /* solution found */ + } else { + /* check of vfields argument done in initialize */ + kdt_jump(this->vfields[eDecide], iByteNo, iBitNo); + } + }/*end if (!iIsDecide)*/ + }/*end for (i = 0; i < iForks; i++ )*/ + + this->dset = FALSE; + PICODBG_TRACE(("problem determining class")); + return -1; /* solution not found, problem determining a class */ +} + + + +/* ************************************************************/ +/* decision tree support functions, mappings */ +/* ************************************************************/ + + +/* size==1 -> MapInByte, size==2 -> MapInWord, + size determined from table type contained in kb. + if the inmaptable is empty, outval = inval */ + +static picoos_uint8 kdtMapInFixed(const kdt_subobj_t *dt, + const picoos_uint8 imtnr, + const picoos_uint16 inval, + picoos_uint16 *outval, + picoos_uint16 *outfallbackval) { + picoos_uint8 size; + picoos_uint32 pos; + picoos_uint16 lentable; + picoos_uint16 posbound; + picoos_uint16 i; + + *outval = 0; + *outfallbackval = 0; + + size = 0; + pos = 0; + + /* check what can be checked */ + if (imtnr >= dt->inpmaptable[pos++]) { /* outside tablenr range? */ + PICODBG_ERROR(("check failed: nrtab: %d, imtnr: %d", + dt->inpmaptable[pos-1], imtnr)); + return FALSE; + } + + /* go forward to the needed tablenr */ + if (imtnr > 0) { + pos = dt->beg_offset[imtnr]; + } + + /* get length */ + lentable = ((picoos_uint16)(dt->inpmaptable[pos+1])) << 8 | + dt->inpmaptable[pos]; + posbound = pos + lentable; + pos += 2; + + /* check type of table and set size */ + if (dt->inpmaptable[pos] == PICOKDT_MTTYPE_EMPTY) { + /* empty table no mapping needed */ + PICODBG_TRACE(("empty table: %d", imtnr)); + *outval = inval; + return TRUE; + } else if (dt->inpmaptable[pos] == PICOKDT_MTTYPE_BYTE) { + size = 1; + } else if (dt->inpmaptable[pos] == PICOKDT_MTTYPE_WORD) { + size = 2; + } else { + /* wrong table type */ + PICODBG_ERROR(("wrong table type %d", dt->inpmaptable[pos])); + return FALSE; + } + pos++; + + /* set fallback value in case of failed mapping, and set upper bound pos */ + *outfallbackval = ((picoos_uint16)(dt->inpmaptable[pos+1])) << 8 | + dt->inpmaptable[pos]; + pos += 2; + + /* size must be 1 or 2 here, keep 'redundant' so save time */ + if (size == 1) { + for (i = 0; (i < *outfallbackval) && (pos < posbound); i++) { + if (inval == dt->inpmaptable[pos]) { + *outval = i; + PICODBG_TRACE(("s1 %d in %d -> out %d", imtnr, inval, *outval)); + return TRUE; + } + pos++; + } + } else if (size == 2) { + posbound--; + for (i = 0; (i < *outfallbackval) && (pos < posbound); i++) { + if (inval == (((picoos_uint16)(dt->inpmaptable[pos+1])) << 8 | + dt->inpmaptable[pos])) { + *outval = i; + PICODBG_TRACE(("s2 %d in %d -> out %d", imtnr, inval, *outval)); + return TRUE; + } + pos += 2; + } + } else { + /* impossible size */ + PICODBG_ERROR(("wrong size %d", size)); + return FALSE; + } + + PICODBG_DEBUG(("no mapping found, fallback: %d", *outfallbackval)); + return FALSE; +} + + +static picoos_uint8 kdtMapInGraph(const kdt_subobj_t *dt, + const picoos_uint8 imtnr, + const picoos_uint8 *inval, + const picoos_uint8 invalmaxlen, + picoos_uint16 *outval, + picoos_uint16 *outfallbackval) { + picoos_uint8 ilen; + picoos_uint8 tlen; + picoos_uint8 cont; + picoos_uint32 pos; + picoos_uint16 lentable; + picoos_uint16 posbound; + picoos_uint16 i; + picoos_uint8 j; + + *outfallbackval = 0; + + pos = 0; + /* check what can be checked */ + if ((imtnr >= dt->inpmaptable[pos++]) || /* outside tablenr range? */ + (invalmaxlen == 0) || /* too short? */ + ((ilen = picobase_det_utf8_length(inval[0])) == 0) || /* invalid? */ + (ilen > invalmaxlen)) { /* not accessible? */ + PICODBG_ERROR(("check failed: nrtab: %d, imtnr: %d, invalmaxlen: %d, " + "ilen: %d", + dt->inpmaptable[pos-1], imtnr, invalmaxlen, ilen)); + return FALSE; + } + + /* go forward to the needed tablenr */ + for (i = 0; i < imtnr; i++) { + lentable = ((picoos_uint16)(dt->inpmaptable[pos+1])) << 8 | + dt->inpmaptable[pos]; + pos += lentable; + } + + /* get length and check type of inpmaptable */ + lentable = ((picoos_uint16)(dt->inpmaptable[pos+1])) << 8 | + dt->inpmaptable[pos]; + posbound = pos + lentable; + pos += 2; + +#if defined(PICO_DEBUG) + if (1) { + int id; + PICODBG_TRACE(("imtnr %d", imtnr)); + for (id = pos-2; id < posbound; id++) { + PICODBG_TRACE(("imtbyte pos %d, %c %d", id - (pos-2), + dt->inpmaptable[id], dt->inpmaptable[id])); + } + } +#endif + + /* check type of table */ + if (dt->inpmaptable[pos] != PICOKDT_MTTYPE_GRAPH) { + /* empty table does not make sense for graph */ + /* wrong table type */ + PICODBG_ERROR(("wrong table type")); + return FALSE; + } + pos++; + + /* set fallback value in case of failed mapping, and set upper bound pos */ + *outfallbackval = ((picoos_uint16)(dt->inpmaptable[pos+1])) << 8 | + dt->inpmaptable[pos]; + pos += 2; + + /* sequential search */ + for (i = 0; (i < *outfallbackval) && (pos < posbound); i++) { + tlen = picobase_det_utf8_length(dt->inpmaptable[pos]); + if ((pos + tlen) > posbound) { + PICODBG_ERROR(("trying outside imt, posb: %d, pos: %d, tlen: %d", + posbound, pos, tlen)); + return FALSE; + } + if (ilen == tlen) { + cont = TRUE; + for (j = 0; cont && (j < ilen); j++) { + if (dt->inpmaptable[pos + j] != inval[j]) { + cont = FALSE; + } + } + if (cont && (j == ilen)) { /* match found */ + *outval = i; + PICODBG_TRACE(("found mapval, posb %d, pos %d, i %d, tlen %d", + posbound, pos, i, tlen)); + return TRUE; + } + } + pos += tlen; + } + PICODBG_DEBUG(("outside imt %d, posb/pos/i: %d/%d/%d, fallback: %d", + imtnr, posbound, pos, i, *outfallbackval)); + return FALSE; +} + + +/* size==1 -> MapOutByte, size==2 -> MapOutWord */ +static picoos_uint8 kdtMapOutFixed(const kdt_subobj_t *dt, + const picoos_uint16 inval, + picoos_uint16 *outval) { + picoos_uint8 size; + picoos_uint16 nr; + + /* no check of lentable vs. nr in initialize done */ + + size = 0; + + /* type */ + nr = dt->outmaptable[PICOKDT_MTPOS_START + PICOKDT_MTPOS_TABLETYPE]; + + /* check type of table and set size */ + if (nr == PICOKDT_MTTYPE_EMPTY) { + /* empty table no mapping needed */ + PICODBG_TRACE(("empty table")); + *outval = inval; + return TRUE; + } else if (nr == PICOKDT_MTTYPE_BYTE) { + size = 1; + } else if (nr == PICOKDT_MTTYPE_WORD) { + size = 2; + } else { + /* wrong table type */ + PICODBG_ERROR(("wrong table type %d", nr)); + return FALSE; + } + + /* number of mapvalues */ + nr = ((picoos_uint16)(dt->outmaptable[PICOKDT_MTPOS_START + + PICOKDT_MTPOS_NUMBER + 1])) << 8 + | dt->outmaptable[PICOKDT_MTPOS_START + PICOKDT_MTPOS_NUMBER]; + + if (inval < nr) { + if (size == 1) { + *outval = dt->outmaptable[PICOKDT_MTPOS_START + + PICOKDT_MTPOS_MAPSTART + (size * inval)]; + } else { + *outval = ((picoos_uint16)(dt->outmaptable[PICOKDT_MTPOS_START + + PICOKDT_MTPOS_MAPSTART + (size * inval) + 1])) << 8 + | dt->outmaptable[PICOKDT_MTPOS_START + + PICOKDT_MTPOS_MAPSTART + (size * inval)]; + } + return TRUE; + } else { + *outval = 0; + return FALSE; + } +} + + +/* size==1 -> ReverseMapOutByte, size==2 -> ReverseMapOutWord */ +/* outmaptable also used to map from decoded tree output domain to + direct tree output domain */ +static picoos_uint8 kdtReverseMapOutFixed(const kdt_subobj_t *dt, + const picoos_uint16 inval, + picoos_uint16 *outval, + picoos_uint16 *outfallbackval) { + picoos_uint8 size; + picoos_uint32 pos; + picoos_uint16 lentable; + picoos_uint16 posbound; + picoos_uint16 i; + + /* no check of lentable vs. nr in initialize done */ + + size = 0; + pos = 0; + *outval = 0; + *outfallbackval = 0; + + if (dt->outmaptable == NULL) { + /* empty table no mapping needed */ + PICODBG_TRACE(("empty table")); + *outval = inval; + return TRUE; + } + + /* check what can be checked */ + if (dt->outmaptable[pos++] != 1) { /* only one omt possible */ + PICODBG_ERROR(("check failed: nrtab: %d", dt->outmaptable[pos-1])); + return FALSE; + } + + /* get length */ + lentable = ((picoos_uint16)(dt->outmaptable[pos+1])) << 8 | + dt->outmaptable[pos]; + posbound = pos + lentable; + pos += 2; + + /* check type of table and set size */ + /* if (dt->outmaptable[pos] == PICOKDT_MTTYPE_EMPTY), in + ...Initialize the omt is set to NULL if not existing, checked + above */ + + if (dt->outmaptable[pos] == PICOKDT_MTTYPE_BYTE) { + size = 1; + } else if (dt->outmaptable[pos] == PICOKDT_MTTYPE_WORD) { + size = 2; + } else { + /* wrong table type */ + PICODBG_ERROR(("wrong table type %d", dt->outmaptable[pos])); + return FALSE; + } + pos++; + + /* set fallback value in case of failed mapping, and set upper bound pos */ + *outfallbackval = ((picoos_uint16)(dt->outmaptable[pos+1])) << 8 | + dt->outmaptable[pos]; + pos += 2; + + /* size must be 1 or 2 here, keep 'redundant' so save time */ + if (size == 1) { + for (i = 0; (i < *outfallbackval) && (pos < posbound); i++) { + if (inval == dt->outmaptable[pos]) { + *outval = i; + PICODBG_TRACE(("s1 inval %d -> outval %d", inval, *outval)); + return TRUE; + } + pos++; + } + } else if (size == 2) { + posbound--; + for (i = 0; (i < *outfallbackval) && (pos < posbound); i++) { + if (inval == (((picoos_uint16)(dt->outmaptable[pos+1])) << 8 | + dt->outmaptable[pos])) { + *outval = i; + PICODBG_TRACE(("s2 inval %d -> outval %d", inval, *outval)); + return TRUE; + } + pos += 2; + } + } else { + /* impossible size */ + PICODBG_ERROR(("wrong size %d", size)); + return FALSE; + } + + PICODBG_DEBUG(("no mapping found, fallback: %d", *outfallbackval)); + return FALSE; +} + + +picoos_uint8 picokdt_dtPosDreverseMapOutFixed(const picokdt_DtPosD this, + const picoos_uint16 inval, + picoos_uint16 *outval, + picoos_uint16 *outfallbackval) { + + kdtposd_subobj_t * dtposd = (kdtposd_subobj_t *)this; + kdt_subobj_t * dt = &(dtposd->dt); + return kdtReverseMapOutFixed(dt,inval, outval, outfallbackval); +} + +/* not yet impl. size==1 -> MapOutByteToVar, + fix: size==2 -> MapOutWordToVar */ +static picoos_uint8 kdtMapOutVar(const kdt_subobj_t *dt, + const picoos_uint16 inval, + picoos_uint8 *nr, + picoos_uint16 *outval, + const picoos_uint16 outvalmaxlen) { + picoos_uint16 pos; + picoos_uint16 off2ind; + picoos_uint16 lentable; + picoos_uint16 nrinbytes; + picoos_uint8 size; + picoos_uint16 offset1; + picoos_uint16 i; + + if (dt->outmaptable == NULL) { + /* empty table not possible */ + PICODBG_ERROR(("no table found")); + return FALSE; + } + + /* nr of tables == 1 already checked in *Initialize, no need here, go + directly to position 1 */ + pos = 1; + + /* get length of table */ + lentable = (((picoos_uint16)(dt->outmaptable[pos + 1])) << 8 | + dt->outmaptable[pos]); + pos += 2; + + /* check table type */ + if (dt->outmaptable[pos] != PICOKDT_MTTYPE_BYTETOVAR) { + /* wrong table type */ + PICODBG_ERROR(("wrong table type %d", dt->outmaptable[pos])); + return FALSE; + } + size = 2; + pos++; + + /* get nr of ele in maptable (= nr of possible invals) */ + nrinbytes = (((picoos_uint16)(dt->outmaptable[pos+1])) << 8 | + dt->outmaptable[pos]); + pos += 2; + + /* check what's checkable */ + if (nrinbytes == 0) { + PICODBG_ERROR(("table with length zero")); + return FALSE; + } else if (inval >= nrinbytes) { + PICODBG_ERROR(("inval %d outside valid range %d", inval, nrinbytes)); + return FALSE; + } + + PICODBG_TRACE(("inval %d, lentable %d, nrinbytes %d, pos %d", inval, + lentable, nrinbytes, pos)); + + /* set off2ind to the position of the start of offset2-val */ + /* offset2 points to start of next ele */ + off2ind = pos + (size*inval); + + /* get number of output values, offset2 - offset1 */ + if (inval == 0) { + offset1 = 0; + } else { + offset1 = (((picoos_uint16)(dt->outmaptable[off2ind - 1])) << 8 | + dt->outmaptable[off2ind - 2]); + } + *nr = (((picoos_uint16)(dt->outmaptable[off2ind + 1])) << 8 | + dt->outmaptable[off2ind]) - offset1; + + PICODBG_TRACE(("offset1 %d, nr %d, pos %d", offset1, *nr, pos)); + + /* set pos to position of 1st value being mapped to */ + pos += (size * nrinbytes) + offset1; + + if ((pos + *nr - 1) > lentable) { + /* outside table, should not happen */ + PICODBG_ERROR(("problem with table index, pos %d, nr %d, len %d", + pos, *nr, lentable)); + return FALSE; + } + if (*nr > outvalmaxlen) { + /* not enough space in outval */ + PICODBG_ERROR(("overflow in outval, %d > %d", *nr, outvalmaxlen)); + return FALSE; + } + + /* finally, copy outmap result to outval */ + for (i = 0; i < *nr; i++) { + outval[i] = dt->outmaptable[pos++]; + } + return TRUE; +} + + + +/* ************************************************************/ +/* decision tree POS prediction (PosP) functions */ +/* ************************************************************/ + +/* number of prefix and suffix graphemes used to construct the input vector */ +#define KDT_POSP_NRGRAPHPREFATT 4 +#define KDT_POSP_NRGRAPHSUFFATT 6 +#define KDT_POSP_NRGRAPHATT 10 + +/* positions of specgraph and nrgraphs attributes */ +#define KDT_POSP_SPECGRAPHATTPOS 10 +#define KDT_POSP_NRGRAPHSATTPOS 11 + + +/* construct PosP input vector + + PosP invec: 12 elements + + prefix 0-3 prefix graphemes (encoded using tree inpmaptable 0-3) + suffix 4-9 suffix graphemes (encoded using tree inpmaptable 4-9) + isspecchar 10 is a special grapheme (e.g. hyphen) inside the word (0/1)? + nr-utf-graphs 11 number of graphemes (ie. UTF8 chars) + + if there are less than 10 graphemes, each grapheme is used only + once, with the suffix having higher priority, ie. elements 0-9 are + filled as follows: + + #graph + 1 0 0 0 0 0 0 0 0 0 1 + 2 0 0 0 0 0 0 0 0 1 2 + 3 0 0 0 0 0 0 0 1 2 3 + 4 0 0 0 0 0 0 1 2 3 4 + 5 0 0 0 0 0 1 2 3 4 5 + 6 0 0 0 0 1 2 3 4 5 6 + 7 1 0 0 0 2 3 4 5 6 7 + 8 1 2 0 0 3 4 5 6 7 8 + 9 1 2 3 0 4 5 6 7 8 9 + 10 1 2 3 4 5 6 7 8 9 10 + 11 1 2 3 4 6 7 8 9 10 11 + ... + + 1-6: Fill chbuf + 7-10: front to invec 1st part, remove front, add rear + >10: remove front, add rear + no more graph -> + while chbuflen>0: + add rear to the last empty slot in 2nd part of invec, remove rear +*/ + + +picoos_uint8 picokdt_dtPosPconstructInVec(const picokdt_DtPosP this, + const picoos_uint8 *graph, + const picoos_uint16 graphlen, + const picoos_uint8 specgraphflag) { + kdtposp_subobj_t *dtposp; + + /* utf8 circular char buffer, used as restricted input deque */ + /* 2nd part of graph invec has KDT_POSP_NRGRAPHSUFFATT elements, */ + /* max of UTF8_MAXLEN bytes per utf8 char */ + picoos_uint8 chbuf[KDT_POSP_NRGRAPHSUFFATT][PICOBASE_UTF8_MAXLEN]; + picoos_uint8 chbrear; /* next free pos */ + picoos_uint8 chbfront; /* next read pos */ + picoos_uint8 chblen; /* empty=0; full=KDT_POSP_NRGRAPHSUFFATT */ + + picoos_uint16 poscg; /* position of current graph (= utf8 char) */ + picoos_uint16 lencg = 0; /* length of current grapheme */ + picoos_uint16 nrutfg; /* number of utf graphemes */ + picoos_uint8 invecpos; /* next element to add in invec */ + picoos_uint16 fallback; /* fallback value for failed graph encodings */ + picoos_uint8 i; + + dtposp = (kdtposp_subobj_t *)this; + chbrear = 0; + chbfront = 0; + chblen = 0; + poscg = 0; + nrutfg = 0; + invecpos = 0; + + PICODBG_DEBUG(("graphlen %d", graphlen)); + + /* not needed, since all elements are set + for (i = 0; i < PICOKDT_NRATT_POSP; i++) { + dtposp->invec[i] = '\x63'; + } + */ + + dtposp->inveclen = 0; + + while ((poscg < graphlen) && + ((lencg = picobase_det_utf8_length(graph[poscg])) > 0)) { + if (chblen >= KDT_POSP_NRGRAPHSUFFATT) { /* chbuf full */ + if (invecpos < KDT_POSP_NRGRAPHPREFATT) { /* prefix not full */ + /* att-encode front utf graph and add in invec */ + if (!kdtMapInGraph(&(dtposp->dt), invecpos, + chbuf[chbfront], PICOBASE_UTF8_MAXLEN, + &(dtposp->invec[invecpos]), + &fallback)) { + if (fallback) { + dtposp->invec[invecpos] = fallback; + } else { + return FALSE; + } + } + invecpos++; + } + /* remove front utf graph */ + chbfront++; + chbfront %= KDT_POSP_NRGRAPHSUFFATT; + chblen--; + } + /* add current utf graph to chbuf */ + for (i=0; i 0) { + + while (invecpos < KDT_POSP_NRGRAPHPREFATT) { /* fill up prefix */ + if (!kdtMapInGraph(&(dtposp->dt), invecpos, + PICOKDT_OUTSIDEGRAPH_DEFSTR, + PICOKDT_OUTSIDEGRAPH_DEFLEN, + &(dtposp->invec[invecpos]), &fallback)) { + if (fallback) { + dtposp->invec[invecpos] = fallback; + } else { + return FALSE; + } + } + invecpos++; + } + + for (i = (KDT_POSP_NRGRAPHATT - 1); + i >= KDT_POSP_NRGRAPHPREFATT; i--) { + if (chblen > 0) { + if (chbrear == 0) { + chbrear = KDT_POSP_NRGRAPHSUFFATT - 1; + } else { + chbrear--; + } + if (!kdtMapInGraph(&(dtposp->dt), i, chbuf[chbrear], + PICOBASE_UTF8_MAXLEN, + &(dtposp->invec[i]), &fallback)) { + if (fallback) { + dtposp->invec[i] = fallback; + } else { + return FALSE; + } + } + chblen--; + } else { + if (!kdtMapInGraph(&(dtposp->dt), i, + PICOKDT_OUTSIDEGRAPH_DEFSTR, + PICOKDT_OUTSIDEGRAPH_DEFLEN, + &(dtposp->invec[i]), &fallback)) { + if (fallback) { + dtposp->invec[i] = fallback; + } else { + return FALSE; + } + } + } + } + + /* set isSpecChar attribute, reuse var i */ + i = (specgraphflag ? 1 : 0); + if (!kdtMapInFixed(&(dtposp->dt), KDT_POSP_SPECGRAPHATTPOS, i, + &(dtposp->invec[KDT_POSP_SPECGRAPHATTPOS]), + &fallback)) { + if (fallback) { + dtposp->invec[KDT_POSP_SPECGRAPHATTPOS] = fallback; + } else { + return FALSE; + } + } + + /* set nrGraphs attribute */ + if (!kdtMapInFixed(&(dtposp->dt), KDT_POSP_NRGRAPHSATTPOS, nrutfg, + &(dtposp->invec[KDT_POSP_NRGRAPHSATTPOS]), + &fallback)) { + if (fallback) { + dtposp->invec[KDT_POSP_NRGRAPHSATTPOS] = fallback; + } else { + return FALSE; + } + } + PICODBG_DEBUG(("posp-invec: [%d,%d,%d,%d|%d,%d,%d,%d,%d,%d|%d|%d]", + dtposp->invec[0], dtposp->invec[1], dtposp->invec[2], + dtposp->invec[3], dtposp->invec[4], dtposp->invec[5], + dtposp->invec[6], dtposp->invec[7], dtposp->invec[8], + dtposp->invec[9], dtposp->invec[10], + dtposp->invec[11])); + dtposp->inveclen = PICOKDT_NRINPMT_POSP; + return TRUE; + } + + return FALSE; +} + + +picoos_uint8 picokdt_dtPosPclassify(const picokdt_DtPosP this) { + picoos_uint32 iByteNo; + picoos_int8 iBitNo; + picoos_int8 rv; + kdtposp_subobj_t *dtposp; + kdt_subobj_t *dt; + + dtposp = (kdtposp_subobj_t *)this; + dt = &(dtposp->dt); + iByteNo = 0; + iBitNo = 7; + while ((rv = kdtAskTree(dt, dtposp->invec, PICOKDT_NRATT_POSP, + &iByteNo, &iBitNo)) > 0) { + PICODBG_TRACE(("asking tree")); + } + PICODBG_DEBUG(("done: %d", dt->dclass)); + return ((rv == 0) && dt->dset); +} + + +picoos_uint8 picokdt_dtPosPdecomposeOutClass(const picokdt_DtPosP this, + picokdt_classify_result_t *dtres) { + kdtposp_subobj_t *dtposp; + picoos_uint16 val; + + dtposp = (kdtposp_subobj_t *)this; + + if (dtposp->dt.dset && + kdtMapOutFixed(&(dtposp->dt), dtposp->dt.dclass, &val)) { + dtres->set = TRUE; + dtres->class = val; + return TRUE; + } else { + dtres->set = FALSE; + return FALSE; + } +} + + + +/* ************************************************************/ +/* decision tree POS disambiguation (PosD) functions */ +/* ************************************************************/ + + +picoos_uint8 picokdt_dtPosDconstructInVec(const picokdt_DtPosD this, + const picoos_uint16 * input) { + kdtposd_subobj_t *dtposd; + picoos_uint8 i; + picoos_uint16 fallback = 0; + + dtposd = (kdtposd_subobj_t *)this; + dtposd->inveclen = 0; + + PICODBG_DEBUG(("in: [%d,%d,%d|%d|%d,%d,%d]", + input[0], input[1], input[2], + input[3], input[4], input[5], + input[6])); + for (i = 0; i < PICOKDT_NRATT_POSD; i++) { + + /* do the imt mapping for all inval */ + if (!kdtMapInFixed(&(dtposd->dt), i, input[i], + &(dtposd->invec[i]), &fallback)) { + if (fallback) { + PICODBG_DEBUG(("*** using fallback for input mapping: %i -> %i", input[i], fallback)); + dtposd->invec[i] = fallback; + } else { + PICODBG_ERROR(("problem doing input mapping")); + return FALSE; + } + } + } + + PICODBG_DEBUG(("out: [%d,%d,%d|%d|%d,%d,%d]", + dtposd->invec[0], dtposd->invec[1], dtposd->invec[2], + dtposd->invec[3], dtposd->invec[4], dtposd->invec[5], + dtposd->invec[6])); + dtposd->inveclen = PICOKDT_NRINPMT_POSD; + return TRUE; +} + + +picoos_uint8 picokdt_dtPosDclassify(const picokdt_DtPosD this, + picoos_uint16 *treeout) { + picoos_uint32 iByteNo; + picoos_int8 iBitNo; + picoos_int8 rv; + kdtposd_subobj_t *dtposd; + kdt_subobj_t *dt; + + dtposd = (kdtposd_subobj_t *)this; + dt = &(dtposd->dt); + iByteNo = 0; + iBitNo = 7; + while ((rv = kdtAskTree(dt, dtposd->invec, PICOKDT_NRATT_POSD, + &iByteNo, &iBitNo)) > 0) { + PICODBG_TRACE(("asking tree")); + } + PICODBG_DEBUG(("done: %d", dt->dclass)); + if ((rv == 0) && dt->dset) { + *treeout = dt->dclass; + return TRUE; + } else { + return FALSE; + } +} + + +/* decompose the tree output and return the class in dtres + dtres: POS classification result + returns: TRUE if okay, FALSE otherwise +*/ +picoos_uint8 picokdt_dtPosDdecomposeOutClass(const picokdt_DtPosD this, + picokdt_classify_result_t *dtres) { + kdtposd_subobj_t *dtposd; + picoos_uint16 val; + + dtposd = (kdtposd_subobj_t *)this; + + if (dtposd->dt.dset && + kdtMapOutFixed(&(dtposd->dt), dtposd->dt.dclass, &val)) { + dtres->set = TRUE; + dtres->class = val; + return TRUE; + } else { + dtres->set = FALSE; + return FALSE; + } +} + + + +/* ************************************************************/ +/* decision tree grapheme-to-phoneme (G2P) functions */ +/* ************************************************************/ + + +/* get the nr'th (starting at 0) utf char in utfgraph */ +static picoos_uint8 kdtGetUTF8char(const picoos_uint8 *utfgraph, + const picoos_uint16 graphlen, + const picoos_uint16 nr, + picoos_uint8 *utf8char) { + picoos_uint16 i; + picoos_uint32 pos; + + pos = 0; + for (i = 0; i < nr; i++) { + if (!picobase_get_next_utf8charpos(utfgraph, graphlen, &pos)) { + return FALSE; + } + } + return picobase_get_next_utf8char(utfgraph, graphlen, &pos, utf8char); +} + +/* determine the utfchar count (starting at 1) of the utfchar starting at pos */ +static picoos_uint16 kdtGetUTF8Nr(const picoos_uint8 *utfgraph, + const picoos_uint16 graphlen, + const picoos_uint16 pos) { + picoos_uint32 postmp; + picoos_uint16 count; + + count = 0; + postmp = 0; + while ((postmp <= pos) && (count < graphlen)) { + if (!picobase_get_next_utf8charpos(utfgraph, graphlen, &postmp)) { + PICODBG_ERROR(("invalid utf8 string, count: %d, pos: %d, post: %d", + count, pos, postmp)); + return count + 1; + } + count++; + } + return count; +} + + +picoos_uint8 picokdt_dtG2PconstructInVec(const picokdt_DtG2P this, + const picoos_uint8 *graph, + const picoos_uint16 graphlen, + const picoos_uint8 count, + const picoos_uint8 pos, + const picoos_uint8 nrvow, + const picoos_uint8 ordvow, + picoos_uint8 *primstressflag, + const picoos_uint16 phonech1, + const picoos_uint16 phonech2, + const picoos_uint16 phonech3) { + kdtg2p_subobj_t *dtg2p; + picoos_uint16 fallback = 0; + picoos_uint8 iAttr; + picoos_uint8 utf8char[PICOBASE_UTF8_MAXLEN + 1]; + picoos_uint16 inval; + picoos_int16 cinv; + picoos_uint8 retval; + picoos_int32 utfgraphlen; + picoos_uint16 utfcount; + + dtg2p = (kdtg2p_subobj_t *)this; + retval = TRUE; + inval = 0; + + PICODBG_TRACE(("in: [%d,%d,%d|%d,%d|%d|%d,%d,%d]", graphlen, count, pos, + nrvow, ordvow, *primstressflag, phonech1, phonech2, + phonech3)); + + dtg2p->inveclen = 0; + + /* many speed-ups possible */ + + /* graph attributes */ + /* count > = <= count + iAttr lowbound eow upbound delta + 0 4 4 graphlen 5 + 1 3 3 graphlen 4 + 2 2 2 graphlen 3 + 3 1 1 graphlen 2 + 4 0 - graphlen 1 + + 5 0 graphlen graphlen-1 0 + 6 0 graphlen-1 graphlen-2 -1 + 7 0 graphlen-2 graphlen-3 -2 + 8 0 graphlen-3 graphlen-4 -3 + */ + + /* graph attributes left (context -4/-3/-2/-1) and current, MapInGraph */ + + utfgraphlen = picobase_utf8_length(graph, graphlen); + if (utfgraphlen <= 0) { + utfgraphlen = 0; + } + utfcount = kdtGetUTF8Nr(graph, graphlen, count); + + cinv = 4; + for (iAttr = 0; iAttr < 5; iAttr++) { + if ((utfcount > cinv) && (utfcount <= utfgraphlen)) { + +/* utf8char[0] = graph[count - cinv - 1];*/ + if (!kdtGetUTF8char(graph, graphlen, utfcount-cinv-1, + utf8char)) { + PICODBG_WARN(("problem getting UTF char %d", utfcount-cinv-1)); + utf8char[0] = PICOKDT_OUTSIDEGRAPH_DEFCH; + utf8char[1] = '\0'; + } + } else { + if ((utfcount == cinv) && (iAttr != 4)) { + utf8char[0] = PICOKDT_OUTSIDEGRAPH_EOW_DEFCH; + } else { + utf8char[0] = PICOKDT_OUTSIDEGRAPH_DEFCH; + } + utf8char[1] = '\0'; + } + + if (!kdtMapInGraph(&(dtg2p->dt), iAttr, + utf8char, PICOBASE_UTF8_MAXLEN, + &(dtg2p->invec[iAttr]), + &fallback)) { + if (fallback) { + dtg2p->invec[iAttr] = fallback; + } else { + PICODBG_WARN(("setting attribute %d to zero", iAttr)); + dtg2p->invec[iAttr] = 0; + retval = FALSE; + } + } + PICODBG_TRACE(("invec %d %c", iAttr, utf8char[0])); + cinv--; + } + + /* graph attributes right (context 1/2/3/4), MapInGraph */ + cinv = utfgraphlen; + for (iAttr = 5; iAttr < 9; iAttr++) { + if ((utfcount > 0) && (utfcount <= (cinv - 1))) { +/* utf8char[0] = graph[count + graphlen - cinv];*/ + if (!kdtGetUTF8char(graph, graphlen, utfcount+utfgraphlen-cinv, + utf8char)) { + PICODBG_WARN(("problem getting UTF char %d", + utfcount+utfgraphlen-cinv-1)); + utf8char[0] = PICOKDT_OUTSIDEGRAPH_DEFCH; + utf8char[1] = '\0'; + } + } else { + if (utfcount == cinv) { + utf8char[0] = PICOKDT_OUTSIDEGRAPH_EOW_DEFCH; + utf8char[1] = '\0'; + } else { + utf8char[0] = PICOKDT_OUTSIDEGRAPH_DEFCH; + utf8char[1] = '\0'; + } + } + if (!kdtMapInGraph(&(dtg2p->dt), iAttr, + utf8char, PICOBASE_UTF8_MAXLEN, + &(dtg2p->invec[iAttr]), + &fallback)) { + if (fallback) { + dtg2p->invec[iAttr] = fallback; + } else { + PICODBG_WARN(("setting attribute %d to zero", iAttr)); + dtg2p->invec[iAttr] = 0; + retval = FALSE; + } + } + PICODBG_TRACE(("invec %d %c", iAttr, utf8char[0])); + cinv--; + } + + /* other attributes, MapInFixed */ + for (iAttr = 9; iAttr < PICOKDT_NRATT_G2P; iAttr++) { + switch (iAttr) { + case 9: /* word POS, Fix1 */ + inval = pos; + break; + case 10: /* nr of vowel-like graphs in word, if vowel, Fix2 */ + inval = nrvow; + break; + case 11: /* order of current vowel-like graph in word, Fix2 */ + inval = ordvow; + break; + case 12: /* primary stress mark, Fix2 */ + if (*primstressflag == 1) { + /*already set previously*/ + inval = 1; + } else { + inval = 0; + } + break; + case 13: /* phone chunk right context +1, Hist */ + inval = phonech1; + break; + case 14: /* phone chunk right context +2, Hist */ + inval = phonech2; + break; + case 15: /* phone chunk right context +3, Hist */ + inval = phonech3; + break; + } + + PICODBG_TRACE(("invec %d %d", iAttr, inval)); + + if (!kdtMapInFixed(&(dtg2p->dt), iAttr, inval, + &(dtg2p->invec[iAttr]), &fallback)) { + if (fallback) { + dtg2p->invec[iAttr] = fallback; + } else { + PICODBG_WARN(("setting attribute %d to zero", iAttr)); + dtg2p->invec[iAttr] = 0; + retval = FALSE; + } + } + } + + PICODBG_TRACE(("out: [%d,%d%,%d,%d|%d|%d,%d,%d,%d|%d,%d,%d,%d|" + "%d,%d,%d]", dtg2p->invec[0], dtg2p->invec[1], + dtg2p->invec[2], dtg2p->invec[3], dtg2p->invec[4], + dtg2p->invec[5], dtg2p->invec[6], dtg2p->invec[7], + dtg2p->invec[8], dtg2p->invec[9], dtg2p->invec[10], + dtg2p->invec[11], dtg2p->invec[12], dtg2p->invec[13], + dtg2p->invec[14], dtg2p->invec[15])); + + dtg2p->inveclen = PICOKDT_NRINPMT_G2P; + return retval; +} + + + + +picoos_uint8 picokdt_dtG2Pclassify(const picokdt_DtG2P this, + picoos_uint16 *treeout) { + picoos_uint32 iByteNo; + picoos_int8 iBitNo; + picoos_int8 rv; + kdtg2p_subobj_t *dtg2p; + kdt_subobj_t *dt; + + dtg2p = (kdtg2p_subobj_t *)this; + dt = &(dtg2p->dt); + iByteNo = 0; + iBitNo = 7; + while ((rv = kdtAskTree(dt, dtg2p->invec, PICOKDT_NRATT_G2P, + &iByteNo, &iBitNo)) > 0) { + PICODBG_TRACE(("asking tree")); + } + PICODBG_TRACE(("done: %d", dt->dclass)); + if ((rv == 0) && dt->dset) { + *treeout = dt->dclass; + return TRUE; + } else { + return FALSE; + } +} + + + +picoos_uint8 picokdt_dtG2PdecomposeOutClass(const picokdt_DtG2P this, + picokdt_classify_vecresult_t *dtvres) { + kdtg2p_subobj_t *dtg2p; + + dtg2p = (kdtg2p_subobj_t *)this; + + if (dtg2p->dt.dset && + kdtMapOutVar(&(dtg2p->dt), dtg2p->dt.dclass, &(dtvres->nr), + dtvres->classvec, PICOKDT_MAXSIZE_OUTVEC)) { + return TRUE; + } else { + dtvres->nr = 0; + return FALSE; + } + return TRUE; +} + + + +/* ************************************************************/ +/* decision tree phrasing (PHR) functions */ +/* ************************************************************/ + +picoos_uint8 picokdt_dtPHRconstructInVec(const picokdt_DtPHR this, + const picoos_uint8 pre2, + const picoos_uint8 pre1, + const picoos_uint8 src, + const picoos_uint8 fol1, + const picoos_uint8 fol2, + const picoos_uint16 nrwordspre, + const picoos_uint16 nrwordsfol, + const picoos_uint16 nrsyllsfol) { + kdtphr_subobj_t *dtphr; + picoos_uint8 i; + picoos_uint16 inval = 0; + picoos_uint16 fallback = 0; + + dtphr = (kdtphr_subobj_t *)this; + PICODBG_DEBUG(("in: [%d,%d|%d|%d,%d|%d,%d,%d]", + pre2, pre1, src, fol1, fol2, + nrwordspre, nrwordsfol, nrsyllsfol)); + dtphr->inveclen = 0; + + for (i = 0; i < PICOKDT_NRATT_PHR; i++) { + switch (i) { + case 0: inval = pre2; break; + case 1: inval = pre1; break; + case 2: inval = src; break; + case 3: inval = fol1; break; + case 4: inval = fol2; break; + case 5: inval = nrwordspre; break; + case 6: inval = nrwordsfol; break; + case 7: inval = nrsyllsfol; break; + default: + PICODBG_ERROR(("size mismatch")); + return FALSE; + break; + } + + /* do the imt mapping for all inval */ + if (!kdtMapInFixed(&(dtphr->dt), i, inval, + &(dtphr->invec[i]), &fallback)) { + if (fallback) { + dtphr->invec[i] = fallback; + } else { + PICODBG_ERROR(("problem doing input mapping")); + return FALSE; + } + } + } + + PICODBG_DEBUG(("out: [%d,%d|%d|%d,%d|%d,%d,%d]", + dtphr->invec[0], dtphr->invec[1], dtphr->invec[2], + dtphr->invec[3], dtphr->invec[4], dtphr->invec[5], + dtphr->invec[6], dtphr->invec[7])); + dtphr->inveclen = PICOKDT_NRINPMT_PHR; + return TRUE; +} + + +picoos_uint8 picokdt_dtPHRclassify(const picokdt_DtPHR this) { + picoos_uint32 iByteNo; + picoos_int8 iBitNo; + picoos_int8 rv; + kdtphr_subobj_t *dtphr; + kdt_subobj_t *dt; + + dtphr = (kdtphr_subobj_t *)this; + dt = &(dtphr->dt); + iByteNo = 0; + iBitNo = 7; + while ((rv = kdtAskTree(dt, dtphr->invec, PICOKDT_NRATT_PHR, + &iByteNo, &iBitNo)) > 0) { + PICODBG_TRACE(("asking tree")); + } + PICODBG_DEBUG(("done: %d", dt->dclass)); + return ((rv == 0) && dt->dset); +} + + +picoos_uint8 picokdt_dtPHRdecomposeOutClass(const picokdt_DtPHR this, + picokdt_classify_result_t *dtres) { + kdtphr_subobj_t *dtphr; + picoos_uint16 val; + + dtphr = (kdtphr_subobj_t *)this; + + if (dtphr->dt.dset && + kdtMapOutFixed(&(dtphr->dt), dtphr->dt.dclass, &val)) { + dtres->set = TRUE; + dtres->class = val; + return TRUE; + } else { + dtres->set = FALSE; + return FALSE; + } +} + + + +/* ************************************************************/ +/* decision tree phono-acoustical model (PAM) functions */ +/* ************************************************************/ + +picoos_uint8 picokdt_dtPAMconstructInVec(const picokdt_DtPAM this, + const picoos_uint8 *vec, + const picoos_uint8 veclen) { + kdtpam_subobj_t *dtpam; + picoos_uint8 i; + picoos_uint16 fallback = 0; + + dtpam = (kdtpam_subobj_t *)this; + + PICODBG_TRACE(("in0: %d %d %d %d %d %d %d %d %d %d", + vec[0], vec[1], vec[2], vec[3], vec[4], + vec[5], vec[6], vec[7], vec[8], vec[9])); + PICODBG_TRACE(("in1: %d %d %d %d %d %d %d %d %d %d", + vec[10], vec[11], vec[12], vec[13], vec[14], + vec[15], vec[16], vec[17], vec[18], vec[19])); + PICODBG_TRACE(("in2: %d %d %d %d %d %d %d %d %d %d", + vec[20], vec[21], vec[22], vec[23], vec[24], + vec[25], vec[26], vec[27], vec[28], vec[29])); + PICODBG_TRACE(("in3: %d %d %d %d %d %d %d %d %d %d", + vec[30], vec[31], vec[32], vec[33], vec[34], + vec[35], vec[36], vec[37], vec[38], vec[39])); + PICODBG_TRACE(("in4: %d %d %d %d %d %d %d %d %d %d", + vec[40], vec[41], vec[42], vec[43], vec[44], + vec[45], vec[46], vec[47], vec[48], vec[49])); + PICODBG_TRACE(("in5: %d %d %d %d %d %d %d %d %d %d", + vec[50], vec[51], vec[52], vec[53], vec[54], + vec[55], vec[56], vec[57], vec[58], vec[59])); + + dtpam->inveclen = 0; + + /* check veclen */ + if (veclen != PICOKDT_NRINPMT_PAM) { + PICODBG_ERROR(("wrong number of input vector elements")); + return FALSE; + } + + for (i = 0; i < PICOKDT_NRATT_PAM; i++) { + + /* do the imt mapping for all vec eles */ + if (!kdtMapInFixed(&(dtpam->dt), i, vec[i], + &(dtpam->invec[i]), &fallback)) { + if (fallback) { + dtpam->invec[i] = fallback; + } else { + PICODBG_ERROR(("problem doing input mapping, %d %d", i,vec[i])); + return FALSE; + } + } + } + + PICODBG_TRACE(("in0: %d %d %d %d %d %d %d %d %d %d", + dtpam->invec[0], dtpam->invec[1], dtpam->invec[2], + dtpam->invec[3], dtpam->invec[4], dtpam->invec[5], + dtpam->invec[6], dtpam->invec[7], dtpam->invec[8], + dtpam->invec[9])); + PICODBG_TRACE(("in1: %d %d %d %d %d %d %d %d %d %d", + dtpam->invec[10], dtpam->invec[11], dtpam->invec[12], + dtpam->invec[13], dtpam->invec[14], dtpam->invec[15], + dtpam->invec[16], dtpam->invec[17], dtpam->invec[18], + dtpam->invec[19])); + PICODBG_TRACE(("in2: %d %d %d %d %d %d %d %d %d %d", + dtpam->invec[20], dtpam->invec[21], dtpam->invec[22], + dtpam->invec[23], dtpam->invec[24], dtpam->invec[25], + dtpam->invec[26], dtpam->invec[27], dtpam->invec[28], + dtpam->invec[29])); + PICODBG_TRACE(("in3: %d %d %d %d %d %d %d %d %d %d", + dtpam->invec[30], dtpam->invec[31], dtpam->invec[32], + dtpam->invec[33], dtpam->invec[34], dtpam->invec[35], + dtpam->invec[36], dtpam->invec[37], dtpam->invec[38], + dtpam->invec[39])); + PICODBG_TRACE(("in4: %d %d %d %d %d %d %d %d %d %d", + dtpam->invec[40], dtpam->invec[41], dtpam->invec[42], + dtpam->invec[43], dtpam->invec[44], dtpam->invec[45], + dtpam->invec[46], dtpam->invec[47], dtpam->invec[48], + dtpam->invec[49])); + PICODBG_TRACE(("in5: %d %d %d %d %d %d %d %d %d %d", + dtpam->invec[50], dtpam->invec[51], dtpam->invec[52], + dtpam->invec[53], dtpam->invec[54], dtpam->invec[55], + dtpam->invec[56], dtpam->invec[57], dtpam->invec[58], + dtpam->invec[59])); + + dtpam->inveclen = PICOKDT_NRINPMT_PAM; + return TRUE; +} + + +picoos_uint8 picokdt_dtPAMclassify(const picokdt_DtPAM this) { + picoos_uint32 iByteNo; + picoos_int8 iBitNo; + picoos_int8 rv; + kdtpam_subobj_t *dtpam; + kdt_subobj_t *dt; + + dtpam = (kdtpam_subobj_t *)this; + dt = &(dtpam->dt); + iByteNo = 0; + iBitNo = 7; + while ((rv = kdtAskTree(dt, dtpam->invec, PICOKDT_NRATT_PAM, + &iByteNo, &iBitNo)) > 0) { + PICODBG_TRACE(("asking tree")); + } + PICODBG_DEBUG(("done: %d", dt->dclass)); + return ((rv == 0) && dt->dset); +} + + +picoos_uint8 picokdt_dtPAMdecomposeOutClass(const picokdt_DtPAM this, + picokdt_classify_result_t *dtres) { + kdtpam_subobj_t *dtpam; + picoos_uint16 val; + + dtpam = (kdtpam_subobj_t *)this; + + if (dtpam->dt.dset && + kdtMapOutFixed(&(dtpam->dt), dtpam->dt.dclass, &val)) { + dtres->set = TRUE; + dtres->class = val; + return TRUE; + } else { + dtres->set = FALSE; + return FALSE; + } +} + + + +/* ************************************************************/ +/* decision tree accentuation (ACC) functions */ +/* ************************************************************/ + +picoos_uint8 picokdt_dtACCconstructInVec(const picokdt_DtACC this, + const picoos_uint8 pre2, + const picoos_uint8 pre1, + const picoos_uint8 src, + const picoos_uint8 fol1, + const picoos_uint8 fol2, + const picoos_uint16 hist1, + const picoos_uint16 hist2, + const picoos_uint16 nrwordspre, + const picoos_uint16 nrsyllspre, + const picoos_uint16 nrwordsfol, + const picoos_uint16 nrsyllsfol, + const picoos_uint16 footwordsfol, + const picoos_uint16 footsyllsfol) { + kdtacc_subobj_t *dtacc; + picoos_uint8 i; + picoos_uint16 inval = 0; + picoos_uint16 fallback = 0; + + dtacc = (kdtacc_subobj_t *)this; + PICODBG_DEBUG(("in: [%d,%d,%d,%d,%d|%d,%d|%d,%d,%d,%d|%d,%d]", + pre2, pre1, src, fol1, fol2, hist1, hist2, + nrwordspre, nrsyllspre, nrwordsfol, nrsyllsfol, + footwordsfol, footsyllsfol)); + dtacc->inveclen = 0; + + for (i = 0; i < PICOKDT_NRATT_ACC; i++) { + switch (i) { + case 0: inval = pre2; break; + case 1: inval = pre1; break; + case 2: inval = src; break; + case 3: inval = fol1; break; + case 4: inval = fol2; break; + case 5: inval = hist1; break; + case 6: inval = hist2; break; + case 7: inval = nrwordspre; break; + case 8: inval = nrsyllspre; break; + case 9: inval = nrwordsfol; break; + case 10: inval = nrsyllsfol; break; + case 11: inval = footwordsfol; break; + case 12: inval = footsyllsfol; break; + default: + PICODBG_ERROR(("size mismatch")); + return FALSE; + break; + } + + if (((i == 5) || (i == 6)) && (inval == PICOKDT_HISTORY_ZERO)) { + /* in input to this function the HISTORY_ZERO is used to + mark the no-value-available case. For sparsity reasons + this was not used in the training. For + no-value-available cases, instead, do reverse out + mapping of ACC0 to get tree domain for ACC0 */ + if (!kdtReverseMapOutFixed(&(dtacc->dt), PICODATA_ACC0, + &inval, &fallback)) { + if (fallback) { + inval = fallback; + } else { + PICODBG_ERROR(("problem doing reverse output mapping")); + return FALSE; + } + } + } + + /* do the imt mapping for all inval */ + if (!kdtMapInFixed(&(dtacc->dt), i, inval, + &(dtacc->invec[i]), &fallback)) { + if (fallback) { + dtacc->invec[i] = fallback; + } else { + PICODBG_ERROR(("problem doing input mapping")); + return FALSE; + } + } + } + + PICODBG_DEBUG(("out: [%d,%d,%d,%d,%d|%d,%d|%d,%d,%d,%d|%d,%d]", + dtacc->invec[0], dtacc->invec[1], dtacc->invec[2], + dtacc->invec[3], dtacc->invec[4], dtacc->invec[5], + dtacc->invec[6], dtacc->invec[7], dtacc->invec[8], + dtacc->invec[9], dtacc->invec[10], dtacc->invec[11], + dtacc->invec[12])); + dtacc->inveclen = PICOKDT_NRINPMT_ACC; + return TRUE; +} + + +picoos_uint8 picokdt_dtACCclassify(const picokdt_DtACC this, + picoos_uint16 *treeout) { + picoos_uint32 iByteNo; + picoos_int8 iBitNo; + picoos_int8 rv; + kdtacc_subobj_t *dtacc; + kdt_subobj_t *dt; + + dtacc = (kdtacc_subobj_t *)this; + dt = &(dtacc->dt); + iByteNo = 0; + iBitNo = 7; + while ((rv = kdtAskTree(dt, dtacc->invec, PICOKDT_NRATT_ACC, + &iByteNo, &iBitNo)) > 0) { + PICODBG_TRACE(("asking tree")); + } + PICODBG_TRACE(("done: %d", dt->dclass)); + if ((rv == 0) && dt->dset) { + *treeout = dt->dclass; + return TRUE; + } else { + return FALSE; + } +} + + +picoos_uint8 picokdt_dtACCdecomposeOutClass(const picokdt_DtACC this, + picokdt_classify_result_t *dtres) { + kdtacc_subobj_t *dtacc; + picoos_uint16 val; + + dtacc = (kdtacc_subobj_t *)this; + + if (dtacc->dt.dset && + kdtMapOutFixed(&(dtacc->dt), dtacc->dt.dclass, &val)) { + dtres->set = TRUE; + dtres->class = val; + return TRUE; + } else { + dtres->set = FALSE; + return FALSE; + } +} + +#ifdef __cplusplus +} +#endif + + +/* end */ diff --git a/pico/lib/picokdt.h b/pico/lib/picokdt.h new file mode 100644 index 0000000..3ef973c --- /dev/null +++ b/pico/lib/picokdt.h @@ -0,0 +1,465 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picokdt.h + * + * knowledge handling for decision trees + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#ifndef PICOKDT_H_ +#define PICOKDT_H_ + +#include "picoos.h" +#include "picoknow.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* ************************************************************/ +/* + Several specialized decision trees kb are provided by this + knowledge handling module: + + - Part of speech prediction decision tree: ...kdt_PosP + - Part of speech disambiguation decision tree: ...kdt_PosD + - Grapheme-to-phoneme decision tree: ...kdt_G2P + - Phrasing decision tree: ...kdt_PHR + - Accentuation decision tree: ...kdt_ACC + these 5 tree types may be unified in the future to a single type + + - Phono-acoustical model trees: ...kdt_PAM + (actually 11 trees, but all have the same characteristics and + are instances of the same class) +*/ +/* ************************************************************/ + + +/* ************************************************************/ +/* defines and functions to create specialized kb, */ +/* to be used by picorsrc only */ +/* ************************************************************/ + +typedef enum { + PICOKDT_KDTTYPE_POSP, + PICOKDT_KDTTYPE_POSD, + PICOKDT_KDTTYPE_G2P, + PICOKDT_KDTTYPE_PHR, + PICOKDT_KDTTYPE_ACC, + PICOKDT_KDTTYPE_PAM +} picokdt_kdttype_t; + +pico_status_t picokdt_specializeDtKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common, + const picokdt_kdttype_t type); + + +/* ************************************************************/ +/* decision tree types (opaque) and get Tree functions */ +/* ************************************************************/ + +/* decision tree types */ +typedef struct picokdt_dtposp * picokdt_DtPosP; +typedef struct picokdt_dtposd * picokdt_DtPosD; +typedef struct picokdt_dtg2p * picokdt_DtG2P; +typedef struct picokdt_dtphr * picokdt_DtPHR; +typedef struct picokdt_dtacc * picokdt_DtACC; +typedef struct picokdt_dtpam * picokdt_DtPAM; + +/* return kb decision tree for usage in PU */ +picokdt_DtPosP picokdt_getDtPosP(picoknow_KnowledgeBase this); +picokdt_DtPosD picokdt_getDtPosD(picoknow_KnowledgeBase this); +picokdt_DtG2P picokdt_getDtG2P (picoknow_KnowledgeBase this); +picokdt_DtPHR picokdt_getDtPHR (picoknow_KnowledgeBase this); +picokdt_DtACC picokdt_getDtACC (picoknow_KnowledgeBase this); +picokdt_DtPAM picokdt_getDtPAM (picoknow_KnowledgeBase this); + + +/* number of attributes (= input vector size) for each tree type */ +typedef enum { + PICOKDT_NRATT_POSP = 12, + PICOKDT_NRATT_POSD = 7, + PICOKDT_NRATT_G2P = 16, + PICOKDT_NRATT_PHR = 8, + PICOKDT_NRATT_ACC = 13, + PICOKDT_NRATT_PAM = 60 +} kdt_nratt_t; + + +/* ************************************************************/ +/* decision tree classification result type */ +/* ************************************************************/ + +typedef struct { + picoos_uint8 set; /* TRUE if class set, FALSE otherwise */ + picoos_uint16 class; +} picokdt_classify_result_t; + + +/* maximum number of output values the tree output is mapped to */ +#define PICOKDT_MAXSIZE_OUTVEC 8 + +typedef struct { + picoos_uint8 nr; /* 0 if no class set, nr of values set otherwise */ + picoos_uint16 classvec[PICOKDT_MAXSIZE_OUTVEC]; +} picokdt_classify_vecresult_t; + + +/* ************************************************************/ +/* decision tree functions */ +/* ************************************************************/ + +/* constructInVec: + for every tree type there is a constructInVec function to construct + the size-optimized input vector for the tree using the input map + tables that are part of the decistion tree knowledge base. The + constructed input vector is stored in the tree object (this->invec + and this->inveclen) and will be used in the following call to the + classify function. + + classify: + for every tree type there is a classify function to apply the + decision tree to the previously constructed input vector. The + size-optimized, encoded output is stored in the tree object + (this->outval) and will be used in the following call to the + decompose function. Where needed (hitory attribute) the direct tree + output is returned by the classify function in a variable. + + decomposeOutClass: + for every tree type there is a decompose function to decompose the + size-optimized, encoded tree output and map it to the outside the + tree usable class value. +*/ + + +/* ************************************************************/ +/* decision tree defines */ +/* ************************************************************/ + +/* to construct the input vectors several hard-coded values are used + to handle attributes that, at the given position, are outside the + context. */ + +/* graph attributes: values to be used if the graph attribute is + outside the grapheme string (ie. word) */ +#define PICOKDT_OUTSIDEGRAPH_DEFCH (picoos_uint8)'\x30' /* ascii "0" */ +#define PICOKDT_OUTSIDEGRAPH_DEFSTR (picoos_uint8 *)"\x30" /* ascii "0" */ +#define PICOKDT_OUTSIDEGRAPH_DEFLEN 1 + +/* graph attributes (special case for g2p): values to be used if the + graph attribute is directly outside the grapheme string (ie. at the + word boundary word). Use PICOKDT_OUTSIDEGRAPH_DEF* if further + outside. */ +#define PICOKDT_OUTSIDEGRAPH_EOW_DEFCH (picoos_uint8)'\x31' /* ascii "1" */ +#define PICOKDT_OUTSIDEGRAPH_EOW_DEFSTR (picoos_uint8 *)"\x31" /* ascii "1" */ +#define PICOKDT_OUTSIDEGRAPH_EOW_DEFLEN 1 + +/* byte and word type attributes: value to be used if a byte or word + attribute is outside the context, e.g. for POS */ +#define PICOKDT_EPSILON 7 + +/* byte and word type attributes: for attribute with history info a + 'zero' value is needed when starting the sequence of predictions. + Use the following value to initialize history. Note that the direct + tree outputs (not mapped with output map table) of previous + predictions need to be used when constructing the input vector for + a following prediction. This direct tree output will then be mapped + together with the rest of the input vector by the input map + table. */ +#define PICOKDT_HISTORY_ZERO 30000 + + +/* ************************************************************/ +/* decision tree POS prediction (PosP) functions */ +/* ************************************************************/ + +/* construct a POS prediction input vector + tree input vector: 0-3 prefix UTF8 graphemes + 4-9 suffex UTF8 graphemes + 10 special grapheme existence flag (TRUE/FALSE) + 11 number of graphemes + graph: the grapheme string of the word for wich POS will be predicted + graphlen: length of graph in number of bytes + specgraphflag: existence of a special grapheme boolean + returns: TRUE if okay, FALSE otherwise + note: use PICOKDT_OUTSIDEGRAPH* for att values outside context +*/ +picoos_uint8 picokdt_dtPosPconstructInVec(const picokdt_DtPosP this, + const picoos_uint8 *graph, + const picoos_uint16 graphlen, + const picoos_uint8 specgraphflag); + + +/* classify a previously constructed input vector using tree 'this' + returns: TRUE if okay, FALSE otherwise +*/ +picoos_uint8 picokdt_dtPosPclassify(const picokdt_DtPosP this); + +/* decompose the tree output and return the class in dtres + dtres: POS or POSgroup ID classification result + returns: TRUE if okay, FALSE otherwise +*/ +picoos_uint8 picokdt_dtPosPdecomposeOutClass(const picokdt_DtPosP this, + picokdt_classify_result_t *dtres); + + +/* ************************************************************/ +/* decision tree POS disambiguation (PosD) functions */ +/* ************************************************************/ + +/* construct a POS disambiguation input vector (run in left-to-right mode) + tree input vector: 0-2 POS or POSgroup for each of the three previous words + 3 POSgroup for current word + 4-6 POS or POSgroup (can be history) for each of + the three following words + pre3 - pre1: POSgroup or POS for the previous three words + src: POSgroup of current word (if unique POS no posdisa possible) + fol1 - fol3: POS or history for the following three words (the more + complicated the better... :-( NEEDS TO BE uint16 + ishist1-ishist3: flag to indicate if fol1-3 are predicted tree + output values (history) or the HISTORY_ZERO (TRUE) + or an already unambiguous POS (FALSE) + returns: TRUE if okay, FALSE otherwise + note: use PICOKDT_EPSILON for att values outside context, + if POS in fol* unique use this POS instead of real + history, use reverse output mapping in these cases +*/ +picoos_uint8 picokdt_dtPosDconstructInVec(const picokdt_DtPosD this, + const picoos_uint16 * input); + + +/* classify a previously constructed input vector using tree 'this' + treeout: direct tree output value + returns: TRUE if okay, FALSE otherwise +*/ +picoos_uint8 picokdt_dtPosDclassify(const picokdt_DtPosD this, + picoos_uint16 *treeout); + +/* decompose the tree output and return the class in dtres + dtres: POS classification result + returns: TRUE if okay, FALSE otherwise +*/ +picoos_uint8 picokdt_dtPosDdecomposeOutClass(const picokdt_DtPosD this, + picokdt_classify_result_t *dtres); + +/* convert (unique) POS index into corresponding tree output index */ +picoos_uint8 picokdt_dtPosDreverseMapOutFixed(const picokdt_DtPosD this, + const picoos_uint16 inval, + picoos_uint16 *outval, + picoos_uint16 *outfallbackval); + +/* ************************************************************/ +/* decision tree grapheme-to-phoneme (G2P) functions */ +/* ************************************************************/ + +/* construct a G2P input vector (run in right-to-left mode) + tree input vector: 0-8 the 4 previous, current, and 4 following graphemes + 9 POS + 10-11 vowel count and vowel ID + 12 primary stress flag (TRUE/FALSE) + 13-15 the three following phones predicted + graph: the grapheme string used to determine invec[0:8] + graphlen: length of graph in number of bytes + count: the grapheme number for which invec will be constructed [0..] + pos: the part of speech of the word + nrvow number of vowel-like graphemes in graph if vowel, + set to 0 otherwise + ordvow order of 'count' vowel in graph if vowel, + set to 0 otherwise + primstressflag: flag indicating if primary stress was already predicted + phonech1-3: the three following phon chunks predicted (right-to-left) + returns: TRUE if okay, FALSE otherwise +*/ +picoos_uint8 picokdt_dtG2PconstructInVec(const picokdt_DtG2P this, + const picoos_uint8 *graph, + const picoos_uint16 graphlen, + const picoos_uint8 count, + const picoos_uint8 pos, + const picoos_uint8 nrvow, + const picoos_uint8 ordvow, + picoos_uint8 *primstressflag, + const picoos_uint16 phonech1, + const picoos_uint16 phonech2, + const picoos_uint16 phonech3); + +/* classify a previously constructed input vector using tree 'this' + treeout: direct tree output value + returns: TRUE if okay, FALSE otherwise +*/ +picoos_uint8 picokdt_dtG2Pclassify(const picokdt_DtG2P this, + picoos_uint16 *treeout); + +/* decompose the tree output and return the class vector in dtvres + dtvres: phones vector classification result + returns: TRUE if okay, FALSE otherwise +*/ +picoos_uint8 picokdt_dtG2PdecomposeOutClass(const picokdt_DtG2P this, + picokdt_classify_vecresult_t *dtvres); + + +/* ************************************************************/ +/* decision tree phrasing (PHR) functions */ +/* ************************************************************/ + +/* construct a PHR input vector (run in right-to-left mode) + tree input vector: 0-1 POS for each of the two previous words + 2 POS for current word + 3-4 POS for each of the two following words + 5 nr words left + 6 nr words right + 7 nr syllables right + pre2 - pre1: POS for the previous two words + src: POS of current word + fol1 - fol2: POS for the following two words + nrwordspre: number of words left (previous) of current word + nrwordsfol: number of words right (following) of current word, + incl. current word, up to next BOUND (also + considering previously predicted PHR2/3) + nrsyllsfol: number of syllables right (following) of current word, + incl. syllables of current word, up to next BOUND + (also considering previously predicted PHR2/3) + returns: TRUE if okay, FALSE otherwise + note: use PICOKDT_EPSILON for att values outside context +*/ +picoos_uint8 picokdt_dtPHRconstructInVec(const picokdt_DtPHR this, + const picoos_uint8 pre2, + const picoos_uint8 pre1, + const picoos_uint8 src, + const picoos_uint8 fol1, + const picoos_uint8 fol2, + const picoos_uint16 nrwordspre, + const picoos_uint16 nrwordsfol, + const picoos_uint16 nrsyllsfol); + +/* classify a previously constructed input vector using tree 'this' + returns: TRUE if okay, FALSE otherwise +*/ +picoos_uint8 picokdt_dtPHRclassify(const picokdt_DtPHR this); + +/* decompose the tree output and return the class vector in dtres + dtres: phrasing classification result + returns: TRUE if okay, FALSE otherwise +*/ +picoos_uint8 picokdt_dtPHRdecomposeOutClass(const picokdt_DtPHR this, + picokdt_classify_result_t *dtres); + + +/* ************************************************************/ +/* decision tree accentuation (ACC) functions */ +/* ************************************************************/ + +/* construct an ACC input vector (run in right-to-left mode) + tree input vector: 0-1 POS for each of the two previous words + 2 POS for current word + 3-4 POS for each of the two following words + 5-6 history values (already predicted following) + 7 nr words left (previous) to any bound + 8 nr syllables left to any bound + 9 nr words right (following) to any bound + 10 nr syllables right to any bound + 11 nr words right to predicted "1" prominence (foot) + 12 nr syllables right to predicted "1" prominence (foot) + pre2 - pre1: POS for the previous two words + src: POS of current word + fol1 - fol2: POS for the following two words + hist1 - hist2: previously predicted ACC values + nrwordspre: number of words left (previous) of current word + nrsyllspre: number of syllables left (previous) of current word, + incl. initial non-prim stress syllables of current word + nrwordsfol: number of words right (following) of current word, + incl. current word, up to next BOUND (any strength != 0) + nrsyllsfol: number of syllables right (following) of current word, + incl. syllables of current word starting with prim. stress + syllable + footwordsfol: nr of words to the following prominence '1' + footsyllspre: nr of syllables to the previous prominence '1' + returns: TRUE if okay, FALSE otherwise + note: use PICOKDT_EPSILON for att 0-4 values outside context +*/ +picoos_uint8 picokdt_dtACCconstructInVec(const picokdt_DtACC this, + const picoos_uint8 pre2, + const picoos_uint8 pre1, + const picoos_uint8 src, + const picoos_uint8 fol1, + const picoos_uint8 fol2, + const picoos_uint16 hist1, + const picoos_uint16 hist2, + const picoos_uint16 nrwordspre, + const picoos_uint16 nrsyllspre, + const picoos_uint16 nrwordsfol, + const picoos_uint16 nrsyllsfol, + const picoos_uint16 footwordsfol, + const picoos_uint16 footsyllsfol); + +/* classify a previously constructed input vector using tree 'this' + treeout: direct tree output value + returns: TRUE if okay, FALSE otherwise +*/ +picoos_uint8 picokdt_dtACCclassify(const picokdt_DtACC this, + picoos_uint16 *treeout); + +/* decompose the tree output and return the class vector in dtres + dtres: phrasing classification result + returns: TRUE if okay, FALSE otherwise +*/ +picoos_uint8 picokdt_dtACCdecomposeOutClass(const picokdt_DtACC this, + picokdt_classify_result_t *dtres); + + +/* ************************************************************/ +/* decision tree phono-acoustical model (PAM) functions */ +/* ************************************************************/ + +/* construct a Pam input vector and store the tree-specific encoded + input vector in the tree object. + vec: tree input vector, 60 single-byte-sized attributes + veclen: length of vec in number of bytes + returns: TRUE if okay, FALSE otherwise +*/ +picoos_uint8 picokdt_dtPAMconstructInVec(const picokdt_DtPAM this, + const picoos_uint8 *vec, + const picoos_uint8 veclen); + +/* classify a previously constructed input vector using tree 'this' + returns: TRUE if okay, FALSE otherwise +*/ +picoos_uint8 picokdt_dtPAMclassify(const picokdt_DtPAM this); + +/* decompose the tree output and return the class in dtres + dtres: phones vector classification result + returns: TRUE if okay, FALSE otherwise +*/ +picoos_uint8 picokdt_dtPAMdecomposeOutClass(const picokdt_DtPAM this, + picokdt_classify_result_t *dtres); + +#ifdef __cplusplus +} +#endif + + + +#endif /*PICOKDT_H_*/ diff --git a/pico/lib/picokfst.c b/pico/lib/picokfst.c new file mode 100644 index 0000000..560709c --- /dev/null +++ b/pico/lib/picokfst.c @@ -0,0 +1,438 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picokfst.c + * + * FST knowledge loading and access + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ +#include "picoos.h" +#include "picodbg.h" +#include "picoknow.h" +#include "picokfst.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +#define FileHdrSize 4 /* size of FST file header */ + + + +/* ************************************************************/ +/* function to create specialized kb, */ +/* to be used by picorsrc only */ +/* ************************************************************/ + +/** object : FSTKnowledgeBase + * shortcut : kfst + * derived from : picoknow_KnowledgeBase + */ + +typedef struct kfst_subobj * kfst_SubObj; + +typedef struct kfst_subobj{ + picoos_uint8 * fstStream; /* the byte stream base address */ + picoos_int32 hdrLen; /* length of file header */ + picoos_int32 transductionMode; /* transduction mode to be used for FST */ + picoos_int32 nrClasses; /* nr of pair/transition classes in FST; class is in [1..nrClasses] */ + picoos_int32 nrStates; /* nr of states in FST; state is in [1..nrState] */ + picoos_int32 termClass; /* pair class of terminator symbol pair; probably obsolete */ + picoos_int32 alphaHashTabSize; /* size of pair alphabet hash table */ + picoos_int32 alphaHashTabPos; /* absolute address of the start of the pair alphabet */ + picoos_int32 transTabEntrySize; /* size in bytes of each transition table entry */ + picoos_int32 transTabPos; /* absolute address of the start of the transition table */ + picoos_int32 inEpsStateTabPos; /* absolute address of the start of the input epsilon transition table */ + picoos_int32 accStateTabPos; /* absolute address of the table of accepting states */ +} kfst_subobj_t; + + + +/* ************************************************************/ +/* primitives for reading from byte stream */ +/* ************************************************************/ + +/* Converts 'nrBytes' bytes starting at position '*pos' in byte stream 'stream' into unsigned number 'num'. + '*pos' is modified to the position right after the number */ +static void FixedBytesToUnsignedNum (picoos_uint8 * stream, picoos_uint8 nrBytes, picoos_uint32 * pos, picoos_uint32 * num) +{ + picoos_int32 i; + + (*num) = 0; + for (i = 0; i < nrBytes; i++) { + (*num) = ((*num) << 8) + (picoos_uint32)stream[*pos]; + (*pos)++; + } +} + + +/* Converts 'nrBytes' bytes starting at position '*pos' in byte stream 'stream' into signed number 'num'. + '*pos' is modified to the position right after the number */ +static void FixedBytesToSignedNum (picoos_uint8 * stream, picoos_uint8 nrBytes, picoos_uint32 * pos, picoos_int32 * num) +{ + picoos_int32 i; + picoos_uint32 val; + + val = 0; + for (i = 0; i < nrBytes; i++) { + val = (val << 8) + (picoos_uint32)stream[*pos]; + (*pos)++; + } + if (val % 2 == 1) { + /* negative number */ + (*num) = -((picoos_int32)((val - 1) / 2)) - 1; + } else { + /* positive number */ + (*num) = val / 2; + } +} + + +/* Converts varying-sized sequence of bytes starting at position '*pos' in byte stream 'stream' + into (signed) number 'num'. '*pos' is modified to the position right after the number. */ +static void BytesToNum (picoos_uint8 * stream, picoos_uint32 * pos, picoos_int32 * num) +{ + picoos_uint32 val; + picoos_uint32 b; + + val = 0; + b = (picoos_uint32)stream[*pos]; + (*pos)++; + while (b < 128) { + val = (val << 7) + b; + b = (picoos_uint32)stream[*pos]; + (*pos)++; + } + val = (val << 7) + (b - 128); + if (val % 2 == 1) { + /* negative number */ + (*num) = -((picoos_int32)((val - 1) / 2)) - 1; + } else { + /* positive number */ + (*num) = val / 2; + } +} + + +/* ************************************************************/ +/* setting up FST from byte stream */ +/* ************************************************************/ + +static pico_status_t kfstInitialize(register picoknow_KnowledgeBase this, + picoos_Common common) +{ + picoos_uint32 curpos; + picoos_int32 offs; + kfst_subobj_t * kfst; + + PICODBG_DEBUG(("kfstInitialize -- start\n")); + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, NULL, + NULL); + } + kfst = (kfst_subobj_t *) this->subObj; + + /* +CT+ */ + kfst->fstStream = this->base; + PICODBG_TRACE(("base: %d\n",this->base)); + kfst->hdrLen = FileHdrSize; + curpos = kfst->hdrLen; + BytesToNum(kfst->fstStream,& curpos,& kfst->transductionMode); + BytesToNum(kfst->fstStream,& curpos,& kfst->nrClasses); + BytesToNum(kfst->fstStream,& curpos,& kfst->nrStates); + BytesToNum(kfst->fstStream,& curpos,& kfst->termClass); + BytesToNum(kfst->fstStream,& curpos,& kfst->alphaHashTabSize); + BytesToNum(kfst->fstStream,& curpos,& offs); + kfst->alphaHashTabPos = kfst->hdrLen + offs; + BytesToNum(kfst->fstStream,& curpos,& kfst->transTabEntrySize); + BytesToNum(kfst->fstStream,& curpos,& offs); + kfst->transTabPos = kfst->hdrLen + offs; + BytesToNum(kfst->fstStream,& curpos,& offs); + kfst->inEpsStateTabPos = kfst->hdrLen + offs; + BytesToNum(kfst->fstStream,& curpos,& offs); + kfst->accStateTabPos = kfst->hdrLen + offs; + /* -CT- */ + + return PICO_OK; +} + + +static pico_status_t kfstSubObjDeallocate(register picoknow_KnowledgeBase this, + picoos_MemoryManager mm) +{ + if (NULL != this) { + picoos_deallocate(mm, (void *) &this->subObj); + } + return PICO_OK; +} + + +/* calculates a small number of data (e.g. addresses) from kb for fast access. + * This data is encapsulated in a picokfst_FST that can later be retrieved + * with picokfst_getFST. */ +pico_status_t picokfst_specializeFSTKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common) +{ + pico_status_t status; + + if (NULL == this) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, NULL, NULL); + } + if (0 < this->size) { + /* not a dummy kb */ + this->subDeallocate = kfstSubObjDeallocate; + + this->subObj = picoos_allocate(common->mm, sizeof(kfst_subobj_t)); + + if (NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, NULL, NULL); + } + status = kfstInitialize(this, common); + if (PICO_OK != status) { + picoos_deallocate(common->mm,(void **)&this->subObj); + } + } + return PICO_OK; +} + + +/* ************************************************************/ +/* FST type and getFST function */ +/* ************************************************************/ + + + +/* return kb FST for usage in PU */ +picokfst_FST picokfst_getFST(picoknow_KnowledgeBase this) +{ + if (NULL == this) { + return NULL; + } else { + return (picokfst_FST) this->subObj; + } +} + + + +/* ************************************************************/ +/* FST access methods */ +/* ************************************************************/ + + +/* see description in header file */ +extern picoos_uint8 picokfst_kfstGetTransductionMode(picokfst_FST this) +{ + kfst_SubObj fst = (kfst_SubObj) this; + if (fst != NULL) { + return fst->transductionMode; + } else { + return 0; + } +} + + +/* see description in header file */ +extern void picokfst_kfstGetFSTSizes (picokfst_FST this, picoos_int32 *nrStates, picoos_int32 *nrClasses) +{ + kfst_SubObj fst = (kfst_SubObj) this; + if (fst != NULL) { + *nrStates = fst->nrStates; + *nrClasses = fst->nrClasses; + } else { + *nrStates = 0; + *nrClasses = 0; + } +} + +/* see description in header file */ +extern void picokfst_kfstStartPairSearch (picokfst_FST this, picokfst_symid_t inSym, + picoos_bool * inSymFound, picoos_int32 * searchState) +{ + picoos_uint32 pos; + picoos_int32 offs; + picoos_int32 h; + picoos_int32 inSymCellPos; + picoos_int32 inSymX; + picoos_int32 nextSameHashInSymOffs; + + kfst_SubObj fst = (kfst_SubObj) this; + (*searchState) = -1; + (*inSymFound) = 0; + h = inSym % fst->alphaHashTabSize; + pos = fst->alphaHashTabPos + (h * 4); + FixedBytesToSignedNum(fst->fstStream,4,& pos,& offs); + if (offs > 0) { + inSymCellPos = fst->alphaHashTabPos + offs; + pos = inSymCellPos; + BytesToNum(fst->fstStream,& pos,& inSymX); + BytesToNum(fst->fstStream,& pos,& nextSameHashInSymOffs); + while ((inSymX != inSym) && (nextSameHashInSymOffs > 0)) { + inSymCellPos = inSymCellPos + nextSameHashInSymOffs; + pos = inSymCellPos; + BytesToNum(fst->fstStream,& pos,& inSymX); + BytesToNum(fst->fstStream,& pos,& nextSameHashInSymOffs); + } + if (inSymX == inSym) { + /* input symbol found; state is set to position after symbol cell */ + (*searchState) = pos; + (*inSymFound) = 1; + } + } +} + + +/* see description in header file */ +extern void picokfst_kfstGetNextPair (picokfst_FST this, picoos_int32 * searchState, + picoos_bool * pairFound, + picokfst_symid_t * outSym, picokfst_class_t * pairClass) +{ + picoos_uint32 pos; + picoos_int32 val; + + kfst_SubObj fst = (kfst_SubObj) this; + if ((*searchState) < 0) { + (*pairFound) = 0; + (*outSym) = PICOKFST_SYMID_ILLEG; + (*pairClass) = -1; + } else { + pos = (*searchState); + BytesToNum(fst->fstStream,& pos,& val); + *outSym = (picokfst_symid_t)val; + if ((*outSym) != PICOKFST_SYMID_ILLEG) { + BytesToNum(fst->fstStream,& pos,& val); + *pairClass = (picokfst_class_t)val; + (*pairFound) = 1; + (*searchState) = pos; + } else { + (*pairFound) = 0; + (*outSym) = PICOKFST_SYMID_ILLEG; + (*pairClass) = -1; + (*searchState) = -1; + } + } +} + + + +/* see description in header file */ +extern void picokfst_kfstGetTrans (picokfst_FST this, picokfst_state_t startState, picokfst_class_t transClass, + picokfst_state_t * endState) +{ + + picoos_uint32 pos; + picoos_int32 index; + picoos_uint32 endStateX; + + kfst_SubObj fst = (kfst_SubObj) this; + if ((startState < 1) || (startState > fst->nrStates) || (transClass < 1) || (transClass > fst->nrClasses)) { + (*endState) = 0; + } else { + index = (startState - 1) * fst->nrClasses + transClass - 1; + pos = fst->transTabPos + (index * fst->transTabEntrySize); + FixedBytesToUnsignedNum(fst->fstStream,fst->transTabEntrySize,& pos,& endStateX); + (*endState) = endStateX; + } +} + + +/* see description in header file */ +extern void picokfst_kfstStartInEpsTransSearch (picokfst_FST this, picokfst_state_t startState, + picoos_bool * inEpsTransFound, picoos_int32 * searchState) +{ + + picoos_int32 offs; + picoos_uint32 pos; + + kfst_SubObj fst = (kfst_SubObj) this; + (*searchState) = -1; + (*inEpsTransFound) = 0; + if ((startState > 0) && (startState <= fst->nrStates)) { + pos = fst->inEpsStateTabPos + (startState - 1) * 4; + FixedBytesToSignedNum(fst->fstStream,4,& pos,& offs); + if (offs > 0) { + (*searchState) = fst->inEpsStateTabPos + offs; + (*inEpsTransFound) = 1; + } + } +} + + + +/* see description in header file */ +extern void picokfst_kfstGetNextInEpsTrans (picokfst_FST this, picoos_int32 * searchState, + picoos_bool * inEpsTransFound, + picokfst_symid_t * outSym, picokfst_state_t * endState) +{ + picoos_uint32 pos; + picoos_int32 val; + + kfst_SubObj fst = (kfst_SubObj) this; + if ((*searchState) < 0) { + (*inEpsTransFound) = 0; + (*outSym) = PICOKFST_SYMID_ILLEG; + (*endState) = 0; + } else { + pos = (*searchState); + BytesToNum(fst->fstStream,& pos,& val); + *outSym = (picokfst_symid_t)val; + if ((*outSym) != PICOKFST_SYMID_ILLEG) { + BytesToNum(fst->fstStream,& pos,& val); + *endState = (picokfst_state_t)val; + (*inEpsTransFound) = 1; + (*searchState) = pos; + } else { + (*inEpsTransFound) = 0; + (*outSym) = PICOKFST_SYMID_ILLEG; + (*endState) = 0; + (*searchState) = -1; + } + } +} + + +/* see description in header file */ +extern picoos_bool picokfst_kfstIsAcceptingState (picokfst_FST this, picokfst_state_t state) +{ + + picoos_uint32 pos; + picoos_uint32 val; + + kfst_SubObj fst = (kfst_SubObj) this; + if ((state > 0) && (state <= fst->nrStates)) { + pos = fst->accStateTabPos + (state - 1); + FixedBytesToUnsignedNum(fst->fstStream,1,& pos,& val); + return (val == 1); + } else { + return 0; + } +} + +#ifdef __cplusplus +} +#endif + +/* End picofst.c */ diff --git a/pico/lib/picokfst.h b/pico/lib/picokfst.h new file mode 100644 index 0000000..b391013 --- /dev/null +++ b/pico/lib/picokfst.h @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picokfst.h + * + * FST knowledge loading and access + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ +#ifndef PICOKFST_H_ +#define PICOKFST_H_ + +#include "picodefs.h" +#include "picodbg.h" +#include "picoos.h" +#include "picoknow.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +typedef picoos_int16 picokfst_symid_t; /* type of symbol identifiers */ +typedef picoos_int16 picokfst_class_t; /* type of symbol pair classes */ +typedef picoos_int16 picokfst_state_t; /* type of states */ + +#define PICOKFST_SYMID_EPS (picokfst_symid_t) 0 /* epsilon symbol id */ +#define PICOKFST_SYMID_ILLEG (picokfst_symid_t) -1 /* illegal symbol id */ + +/** + * @addtogroup picokfst + * + * Mapping of values to FST symbol id (relevant for compiling the FST) \n + * Value FST symbol id \n + * -------------------------------------- \n + * phoneme_id -> phoneme_id + 256 * PICOKFST_PLANE_PHONEMES \n + * accentlevel_id -> accentlevel_id + 256 * PICOKFST_PLANE_ACCENTS \n + * POS_id -> POS_id + 256 * PICOKFST_PLANE_POS \n + * pb_strength_id -> pb_strength_id + 256 * PICOKFST_PLANE_PB_STRENGTHS \n + * phon_term_id -> phon_term_id + 256 * PICOKFST_PLANE_INTERN \n +*/ +enum picokfst_symbol_plane { + PICOKFST_PLANE_PHONEMES = 0, /* phoneme plane */ + PICOKFST_PLANE_ASCII = 1, /* "ascii" plane (values > 127 may be used internally) */ + PICOKFST_PLANE_XSAMPA = 2, /* x-sampa primitives plane (pico-specific table) */ + PICOKFST_PLANE_ACCENTS = 4, /* accent plane */ + PICOKFST_PLANE_POS = 5, /* part of speech plane */ + PICOKFST_PLANE_PB_STRENGTHS = 6, /* phrase boundary strength plane */ + PICOKFST_PLANE_INTERN = 7 /* internal plane, e.g. phonStartId, phonTermId */ +}; + +/* to be used as bit set, e.g. + * picoos_uint8 transductionMode = PICOKFST_TRANSMODE_NEWSYMS | PICOKFST_TRANSMODE_POSUSED; + */ +enum picofst_transduction_mode { + PICOKFST_TRANSMODE_NEWSYMS = 1, /* e.g. {#WB},{#PB-S},{#PB-W},{#ACC0},{#ACC1},{#ACC2},{#ACC3}, */ + PICOKFST_TRANSMODE_POSUSED = 2 /* FST contains Part Of Speech symbols */ + +}; + + +/* ************************************************************/ +/* function to create specialized kb, */ +/* to be used by knowledge layer (picorsrc) only */ +/* ************************************************************/ + +/* calculates a small number of data (e.g. addresses) from kb for fast access. + * This data is encapsulated in a picokfst_FST that can later be retrieved + * with picokfst_getFST. */ +pico_status_t picokfst_specializeFSTKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common); + + +/* ************************************************************/ +/* FST type and getFST function */ +/* ************************************************************/ + +/* FST type */ +typedef struct picokfst_fst * picokfst_FST; + +/* return kb FST for usage in PU */ +picokfst_FST picokfst_getFST(picoknow_KnowledgeBase this); + + +/* ************************************************************/ +/* FST access methods */ +/* ************************************************************/ + +/* returns transduction mode specified with rule sources; + result to be interpreted as set of picofst_transduction_mode */ +picoos_uint8 picokfst_kfstGetTransductionMode(picokfst_FST this); + +/* returns number of states and number of pair classes in FST; + legal states are 1..nrStates, legal classes are 1..nrClasses */ +void picokfst_kfstGetFSTSizes (picokfst_FST this, picoos_int32 *nrStates, picoos_int32 *nrClasses); + +/* starts search for all pairs with input symbol 'inSym'; '*inSymFound' returns whether + such pairs exist at all; '*searchState' returns a search state to be used in + subsequent calls to function 'picokfst_kfstGetNextPair', which must be used + to get the symbol pairs */ +void picokfst_kfstStartPairSearch (picokfst_FST this, picokfst_symid_t inSym, + picoos_bool * inSymFound, picoos_int32 * searchState); + +/* gets next pair for input symbol specified with preceding call to 'picokfst_kfstStartPairSearch'; + '*searchState' maintains the search state, 'pairFound' returns whether any more pair was found, + '*outSym' returns the output symbol of the found pair, and '*pairClass' returns the + transition class of the found symbol pair */ +void picokfst_kfstGetNextPair (picokfst_FST this, picoos_int32 * searchState, + picoos_bool * pairFound, + picokfst_symid_t * outSym, picokfst_class_t * pairClass); + +/* attempts to do FST transition from state 'startState' with pair class 'transClass'; + if such a transition exists, 'endState' returns the end state of the transition (> 0), + otherwise 'endState' returns <= 0 */ +void picokfst_kfstGetTrans (picokfst_FST this, picokfst_state_t startState, picokfst_class_t transClass, + picokfst_state_t * endState); + +/* starts search for all pairs with input epsilon symbol and all correponding + FST transitions starting in state 'startState'; to be used for fast + computation of epsilon closures; + '*inEpsTransFound' returns whether any such transition was found at all; + if so, '*searchState' returns a search state to be used in subsequent calls + to 'picokfst_kfstGetNextInEpsTrans' */ +void picokfst_kfstStartInEpsTransSearch (picokfst_FST this, picokfst_state_t startState, + picoos_bool * inEpsTransFound, picoos_int32 * searchState); + +/* gets next FST transition with a pair with empty input symbol starting from a state + previoulsy specified in 'picokfst_kfstStartInEpsTransSearch'; + '*searchState' maintains the search state, '*inEpsTransFound' returns + whether a new transition with input epsilon was found, '*outSym 'returns + the output symbol of the found pair, and '*endState' returns the end state + of the found transition with that pair */ +void picokfst_kfstGetNextInEpsTrans (picokfst_FST this, picoos_int32 * searchState, + picoos_bool * inEpsTransFound, + picokfst_symid_t * outSym, picokfst_state_t * endState); + +/* returns whether 'state' is an accepting state of FST; originally, only + state 1 was an accepting state; however, in order to remove the need to + always do a last transition with a termination symbol pair, this function + defines a state as an accepting state if there is transition to state 1 + with the terminator symbol pair */ +picoos_bool picokfst_kfstIsAcceptingState (picokfst_FST this, picokfst_state_t state); + +#ifdef __cplusplus +} +#endif + + +#endif /*PICOKFST_H_*/ diff --git a/pico/lib/picoklex.c b/pico/lib/picoklex.c new file mode 100644 index 0000000..3f248b5 --- /dev/null +++ b/pico/lib/picoklex.c @@ -0,0 +1,572 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picoklex.c + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ +#include "picoos.h" +#include "picodbg.h" +#include "picodata.h" +#include "picoknow.h" +#include "picoklex.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +/* ************************************************************/ +/* lexicon */ +/* ************************************************************/ + +/** + * @addtogroup picolex + * + overview: + - lex consists of optional searchindex and a non-empty list of lexblocks + - lexblocks are fixed size, at the start of a block there is also the + start of an entry + - using the searchindex a unambiguous lexblock can be determined which + contains the entry (or there is no entry) + - one lex entry has POS GRAPH PHON, all mandatory, but + - PHON can be empty string -> no pronunciation in the resulting TTS output + - PHON can be :G2P -> use G2P later to add pronunciation + - (POS,GRAPH) is a uniq key (only one entry allowed) + - (GRAPH) is almost a uniq key (2-4 entries with the same GRAPH, and + differing POS and differing PHON possible) + - for one graph we can have two or three solutions from the lex + which all need to be passed on the the next PU + - in this case GRAPH, POS, and PHON all must be available in lex + + sizing: + - 3 bytes entry index -> 16MB addressable + - 2 bytes searchindex nr -> 64K blocks possible + - 5 bytes per searchindex entry + - 3 bytes for graph-prefix + - 2 bytes blockadr in searchindex -> 64K blocks possible + - lexblock size 512B: + - 32M possible + - with ~20 bytes per entry + -> max. average of ~26 entries to be searched per lookup + - overhead of ~10 bytes per block to sync with + block boundaries + - examples: + - 500KB lex -> 1000 blocks, + 1000 entries in searchindex, ~25.6K lex-entries, + - ~5KB searchindex + ~10KB overhead for block sync + - 100KB lex -> 200 blocks, + 200 entries in searchindex, ~5.1K lex-entries, + - ~1KB searchindex + ~2KB overhead for block sync + + pil-file: lexicon knowledge base in binary form + + lex-kb = content + + content = searchindex {lexblock}1:NRBLOCKS2 + + lexblock = {lexentry}1: (lexblock size is fixed 512Bytes) + + searchindex = NRBLOCKS2 {GRAPH1 GRAPH1 GRAPH1 LEXBLOCKIND2}=NRBLOCKS2 + + lexentry = LENGRAPH1 {GRAPH1}=LENGRAPH1-1 + LENPOSPHON1 POS1 {PHON1}=LENPOSPHON1-2 + + - special cases: + - PHON is empty string (no pronunciation in the resulting TTS output): + lexentry = LENGRAPH1 {GRAPH1}=LENGRAPH1-1 2 POS1 + - PHON can be :G2P -> use G2P later to add pronunciation: + lexentry = LENGRAPH1 {GRAPH1}=LENGRAPH1-1 3 POS1 + - multi-byte values always little endian +*/ + + +/* ************************************************************/ +/* lexicon data defines */ +/* may not be changed with current implementation */ +/* ************************************************************/ + +/* nr bytes of nrblocks info */ +#define PICOKLEX_LEX_NRBLOCKS_SIZE 2 + +/* search index entry: - nr graphs + - nr bytes of block index + - nr bytes per entry, NRGRAPHS*INDSIZE */ +#define PICOKLEX_LEX_SIE_NRGRAPHS 3 +#define PICOKLEX_LEX_SIE_INDSIZE 2 +#define PICOKLEX_LEX_SIE_SIZE 5 + +/* nr of bytes per lexblock */ +#define PICOKLEX_LEXBLOCK_SIZE 512 + + +/* reserved values in klex to indicate :G2P needed for a lexentry */ +#define PICOKLEX_NEEDS_G2P 5 + + +/* ************************************************************/ +/* lexicon type and loading */ +/* ************************************************************/ + +/** object : LexKnowledgeBase + * shortcut : klex + * derived from : picoknow_KnowledgeBase + */ + +typedef struct klex_subobj *klex_SubObj; + +typedef struct klex_subobj +{ + picoos_uint16 nrblocks; /* nr lexblocks = nr eles in searchind */ + picoos_uint8 *searchind; + picoos_uint8 *lexblocks; +} klex_subobj_t; + + +static pico_status_t klexInitialize(register picoknow_KnowledgeBase this, + picoos_Common common) +{ + picoos_uint32 curpos = 0; + klex_subobj_t *klex; + + PICODBG_DEBUG(("start")); + + /* check whether (this->size != 0) done before calling this function */ + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + klex = (klex_subobj_t *) this->subObj; + + if (PICO_OK == picoos_read_mem_pi_uint16(this->base, &curpos, + &(klex->nrblocks))) { + if (klex->nrblocks > 0) { + PICODBG_DEBUG(("nr blocks: %i, curpos: %i", klex->nrblocks,curpos)); + klex->searchind = this->base + curpos; + } else { + klex->searchind = NULL; + } + klex->lexblocks = this->base + PICOKLEX_LEX_NRBLOCKS_SIZE + + (klex->nrblocks * (PICOKLEX_LEX_SIE_SIZE)); + return PICO_OK; + } else { + return picoos_emRaiseException(common->em, PICO_EXC_FILE_CORRUPT, + NULL, NULL); + } +} + + +static pico_status_t klexSubObjDeallocate(register picoknow_KnowledgeBase this, + picoos_MemoryManager mm) +{ + if (NULL != this) { + picoos_deallocate(mm, (void *) &this->subObj); + } + return PICO_OK; +} + + +/* we don't offer a specialized constructor for a LexKnowledgeBase but + * instead a "specializer" of an allready existing generic + * picoknow_KnowledgeBase */ + +pico_status_t picoklex_specializeLexKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common) +{ + if (NULL == this) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + if (this->size > 0) { + this->subDeallocate = klexSubObjDeallocate; + this->subObj = picoos_allocate(common->mm, sizeof(klex_subobj_t)); + if (NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, + NULL, NULL); + } + return klexInitialize(this, common); + } else { + /* some dummy klex */ + return PICO_OK; + } +} + +/* for now we don't need to do anything special for the main lex */ +/* +pico_status_t picoklex_specializeMainLexKnowledgeBase( + picoknow_KnowledgeBase this, + picoos_Common common) +{ + return picoklex_specializeLexKnowledgeBase(this,common); +} +*/ + + +/* ************************************************************/ +/* lexicon getLex */ +/* ************************************************************/ + +picoklex_Lex picoklex_getLex(picoknow_KnowledgeBase this) +{ + if (NULL == this) { + return NULL; + } else { + return (picoklex_Lex) this->subObj; + } +} + + +/* ************************************************************/ +/* functions on searchindex */ +/* ************************************************************/ + + +static picoos_uint32 klex_getSearchIndexVal(const klex_SubObj this, + picoos_uint16 index) +{ + picoos_uint32 pos, val; + pos = index * PICOKLEX_LEX_SIE_SIZE; + val = this->searchind[pos]; + val = (val << 8) + this->searchind[pos + 1]; + val = (val << 8) + this->searchind[pos + 2]; + return val; +} + + +/* Determine first lexblock containing entries for specified + grapheme. */ + +static picoos_uint16 klex_getLexblockNr(const klex_SubObj this, + const picoos_uint8 *graphsi) { + /* graphsi is of len PICOKLEX_LEX_SI_NGRAPHS */ + picoos_int32 low, mid, high; + picoos_uint32 searchval, indval; + + /* PICOKLEX_LEX_SIE_NRGRAPHS */ + + /* convert graph-prefix to number with 'lexicographic' ordering */ + searchval = graphsi[0]; + searchval = (searchval << 8) + graphsi[1]; + searchval = (searchval << 8) + graphsi[2]; + + low = 0; + high = this->nrblocks; + + /* do binary search */ + while (low < high) { + mid = (low + high) / 2; + indval = klex_getSearchIndexVal(this, mid); + if (indval < searchval) { + low = mid + 1; + } else { + high = mid; + } + } + PICODBG_ASSERT(high == low); + /* low points to the first entry greater than or equal to searchval */ + + if (low < this->nrblocks) { + indval = klex_getSearchIndexVal(this, low); + if (indval > searchval) { + low--; + /* if there are identical elements in the search index we have + to move to the first one */ + if (low > 0) { + indval = klex_getSearchIndexVal(this, low); + while (indval == klex_getSearchIndexVal(this, low-1)) { + low--; + } + } + } + } else { + low = this->nrblocks - 1; + } + +#if defined(PICO_DEBUG) + { + picoos_uint32 pos = low * PICOKLEX_LEX_SIE_SIZE; + PICODBG_DEBUG(("binary search result is %c%c%c (%d)", + this->searchind[pos], this->searchind[pos + 1], + this->searchind[pos + 2], low)); + } +#endif + + return (picoos_uint16) low; +} + + +/* Determine number of adjacent lexblocks containing entries for + the same grapheme search prefix (identified by search index). */ + +static picoos_uint16 klex_getLexblockRange(const klex_SubObj this, + picoos_uint16 index) +{ + picoos_uint16 count; + picoos_uint32 sval1, sval2; + + sval1 = klex_getSearchIndexVal(this, index); + +#if defined(PICO_DEBUG) + /* 'index' must point to first lexblock of its kind */ + if (index > 0) { + sval2 = klex_getSearchIndexVal(this, index - 1); + PICODBG_ASSERT(sval1 != sval2); + } +#endif + + index++; + sval2 = klex_getSearchIndexVal(this, index); + + count = 1; + while (sval1 == sval2) { + count++; + index++; + sval2 = klex_getSearchIndexVal(this, index); + } + + return count; +} + + +/* ************************************************************/ +/* functions on single lexblock */ +/* ************************************************************/ + +static picoos_int8 klex_lexMatch(picoos_uint8 *lexentry, + const picoos_uint8 *graph, + const picoos_uint16 graphlen) { + picoos_uint8 i; + picoos_uint8 lexlen; + picoos_uint8 *lexgraph; + + lexlen = lexentry[0] - 1; + lexgraph = &(lexentry[1]); + for (i=0; (i graph[i]) { + return 1; + } + } + if (graphlen == lexlen) { + return 0; + } else if (lexlen < graphlen) { + return -1; + } else { + return 1; + } +} + + +static void klex_setLexResult(const picoos_uint8 *lexentry, + const picoos_uint32 lexpos, + picoklex_lexl_result_t *lexres) { + picoos_uint8 i; + + /* check if :G2P */ + if ((2 < (lexentry[lexentry[0]])) && ((lexentry[lexentry[0] + 2]) == PICOKLEX_NEEDS_G2P)) { + /* set pos */ + lexres->posind[0] = lexentry[lexentry[0] + 1]; + /* set rest */ + lexres->phonfound = FALSE; + lexres->posindlen = 1; + lexres->nrres = 1; + PICODBG_DEBUG(("result %d :G2P", lexres->nrres)); + } else { + i = lexres->nrres * (PICOKLEX_POSIND_SIZE); + lexres->posindlen += PICOKLEX_POSIND_SIZE; + lexres->phonfound = TRUE; + /* set pos */ + lexres->posind[i++] = lexentry[lexentry[0] + 1]; + /* set ind, PICOKLEX_IND_SIZE */ + lexres->posind[i++] = 0x000000ff & (lexpos); + lexres->posind[i++] = 0x000000ff & (lexpos >> 8); + lexres->posind[i] = 0x000000ff & (lexpos >> 16); + lexres->nrres++; + PICODBG_DEBUG(("result %d", lexres->nrres)); + } +} + + +static void klex_lexblockLookup(klex_SubObj this, + const picoos_uint32 lexposStart, + const picoos_uint32 lexposEnd, + const picoos_uint8 *graph, + const picoos_uint16 graphlen, + picoklex_lexl_result_t *lexres) { + picoos_uint32 lexpos; + picoos_int8 rv; + + lexres->nrres = 0; + + lexpos = lexposStart; + rv = -1; + while ((rv < 0) && (lexpos < lexposEnd)) { + + rv = klex_lexMatch(&(this->lexblocks[lexpos]), graph, graphlen); + + if (rv == 0) { /* found */ + klex_setLexResult(&(this->lexblocks[lexpos]), lexpos, lexres); + if (lexres->phonfound) { + /* look for more results, up to MAX_NRRES, don't even + check if more results would be available */ + while ((lexres->nrres < PICOKLEX_MAX_NRRES) && + (lexpos < lexposEnd)) { + lexpos += this->lexblocks[lexpos]; + lexpos += this->lexblocks[lexpos]; + /* if there are no more entries in this block, advance + to next block by skipping all zeros */ + while ((this->lexblocks[lexpos] == 0) && + (lexpos < lexposEnd)) { + lexpos++; + } + if (lexpos < lexposEnd) { + if (klex_lexMatch(&(this->lexblocks[lexpos]), graph, + graphlen) == 0) { + klex_setLexResult(&(this->lexblocks[lexpos]), + lexpos, lexres); + } else { + /* no more results, quit loop */ + lexpos = lexposEnd; + } + } + } + } else { + /* :G2P mark */ + } + } else if (rv < 0) { + /* not found, goto next entry */ + lexpos += this->lexblocks[lexpos]; + lexpos += this->lexblocks[lexpos]; + /* if there are no more entries in this block, advance + to next block by skipping all zeros */ + while ((this->lexblocks[lexpos] == 0) && (lexpos < lexposEnd)) { + lexpos++; + } + } else { + /* rv > 0, not found, won't show up later in block */ + } + } +} + + +/* ************************************************************/ +/* lexicon lookup functions */ +/* ************************************************************/ + +picoos_uint8 picoklex_lexLookup(const picoklex_Lex this, + const picoos_uint8 *graph, + const picoos_uint16 graphlen, + picoklex_lexl_result_t *lexres) { + picoos_uint16 lbnr, lbc; + picoos_uint32 lexposStart, lexposEnd; + picoos_uint8 i; + picoos_uint8 tgraph[PICOKLEX_LEX_SIE_NRGRAPHS]; + klex_SubObj klex = (klex_SubObj) this; + + if (NULL == klex) { + PICODBG_ERROR(("no lexicon loaded")); + /* no exception here needed, already checked at initialization */ + return FALSE; + } + + lexres->nrres = 0; + lexres->posindlen = 0; + lexres->phonfound = FALSE; + + for (i = 0; inrblocks) == 0) { + /* no searchindex, no lexblock */ + PICODBG_WARN(("no searchindex, no lexblock")); + return FALSE; + } else { + lbnr = klex_getLexblockNr(klex, tgraph); + PICODBG_ASSERT(lbnr < klex->nrblocks); + lbc = klex_getLexblockRange(klex, lbnr); + PICODBG_ASSERT((lbc >= 1) && (lbc <= klex->nrblocks)); + } + PICODBG_DEBUG(("lexblock nr: %d (#%d)", lbnr, lbc)); + + lexposStart = lbnr * PICOKLEX_LEXBLOCK_SIZE; + lexposEnd = lexposStart + lbc * PICOKLEX_LEXBLOCK_SIZE; + + PICODBG_DEBUG(("lookup start, lexpos range %d..%d", lexposStart,lexposEnd)); + klex_lexblockLookup(klex, lexposStart, lexposEnd, graph, graphlen, lexres); + PICODBG_DEBUG(("lookup done, %d found", lexres->nrres)); + + return (lexres->nrres > 0); +} + + +picoos_uint8 picoklex_lexIndLookup(const picoklex_Lex this, + const picoos_uint8 *ind, + const picoos_uint8 indlen, + picoos_uint8 *pos, + picoos_uint8 **phon, + picoos_uint8 *phonlen) { + picoos_uint32 pentry; + klex_SubObj klex = (klex_SubObj) this; + + /* check indlen */ + if (indlen != PICOKLEX_IND_SIZE) { + return FALSE; + } + + /* PICOKLEX_IND_SIZE */ + pentry = 0x000000ff & (ind[0]); + pentry |= ((picoos_uint32)(ind[1]) << 8); + pentry |= ((picoos_uint32)(ind[2]) << 16); + + /* check ind if it is within lexblocks byte stream, if not, return FALSE */ + if (pentry >= ((picoos_uint32)klex->nrblocks * PICOKLEX_LEXBLOCK_SIZE)) { + return FALSE; + } + + pentry += (klex->lexblocks[pentry]); + *phonlen = (klex->lexblocks[pentry++]) - 2; + *pos = klex->lexblocks[pentry++]; + *phon = &(klex->lexblocks[pentry]); + + PICODBG_DEBUG(("pentry: %d, phonlen: %d", pentry, *phonlen)); + return TRUE; +} + +#ifdef __cplusplus +} +#endif + + +/* end */ diff --git a/pico/lib/picoklex.h b/pico/lib/picoklex.h new file mode 100644 index 0000000..e186393 --- /dev/null +++ b/pico/lib/picoklex.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picoklex.h + * + * knowledge base: lexicon + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#ifndef PICOKLEX_H_ +#define PICOKLEX_H_ + +#include "picoos.h" +#include "picoknow.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* ************************************************************/ +/* function to create specialized kb, */ +/* to be used by picorsrc only */ +/* ************************************************************/ + +pico_status_t picoklex_specializeLexKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common); + + +/* ************************************************************/ +/* lexicon type and getLex function */ +/* ************************************************************/ + +/* lexicon type */ +typedef struct picoklex_lex * picoklex_Lex; + +/* return kb lex for usage in PU */ +picoklex_Lex picoklex_getLex(picoknow_KnowledgeBase this); + + +/* ************************************************************/ +/* lexicon lookup result type */ +/* ************************************************************/ + +/* max nr of results */ +#define PICOKLEX_MAX_NRRES 4 + +/* nr of bytes used for pos and index, needs to fit in uint32, ie. max 4 */ +#define PICOKLEX_POSIND_SIZE 4 +/* nr of bytes used for index, needs to fit in uint32, ie. max 4 */ +#define PICOKLEX_IND_SIZE 3 +/* max len (in bytes) of ind, (PICOKLEX_MAX_NRRES * PICOKLEX_POSIND_SIZE) */ +#define PICOKLEX_POSIND_MAXLEN 16 + + +/* the lexicon lookup result(s) are stored in field posind, which + contains a sequence of + POS1-byte, IND1-bytes, POS2-byte, IND2-bytes, etc. + + the IND-bytes are the byte position(s) in the lexblocks part of the + lexicon byte stream, starting at picoklex_lex_t.lexblocks. + + for lexentries without phones only the POS (there can be only one) + is stored in posind, nrres equals one, and phonfound is FALSE. +*/ + +typedef struct { + picoos_uint8 nrres; /* number of results, 0 of no entry found */ + picoos_uint8 posindlen; /* number of posind bytes */ + picoos_uint8 phonfound; /* phones found flag, TRUE if found */ + picoos_uint8 posind[PICOKLEX_POSIND_MAXLEN]; /* sequence of multi-ind, + one per result */ +} picoklex_lexl_result_t; + + +/* ************************************************************/ +/* lexicon lookup functions */ +/* ************************************************************/ + +/** lookup lex by graph; result(s) are in lexres, ie. the phones are + not returned directly (because they are used later and space can be + saved using indices first), lexres contains an index (or several) + to the entry for later fast lookup once the phones are needed. + PICOKLEX_IND_SIZE bytes are used for the index, these ind bytes are + saved in the WORDINDEX items. If at least one entry is found TRUE + is returned, FALSE otherwise */ +picoos_uint8 picoklex_lexLookup(const picoklex_Lex this, + const picoos_uint8 *graph, + const picoos_uint16 graphlen, + picoklex_lexl_result_t *lexres); + +/** lookup lex entry by index ind; ind is a sequence of bytes with + length indlen (must be equal PICOKLEX_IND_SIZE) that is the content + of a WORDINDEX item. Returns TRUE if okay, FALSE otherwise */ +picoos_uint8 picoklex_lexIndLookup(const picoklex_Lex this, + const picoos_uint8 *ind, + const picoos_uint8 indlen, + picoos_uint8 *pos, + picoos_uint8 **phon, + picoos_uint8 *phonlen); + +#ifdef __cplusplus +} +#endif + + +#endif /*PICOKLEX_H_*/ diff --git a/pico/lib/picoknow.c b/pico/lib/picoknow.c new file mode 100644 index 0000000..70b471c --- /dev/null +++ b/pico/lib/picoknow.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picoknow.c + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include "picodefs.h" +#include "picoos.h" +#include "picodbg.h" +#include "picoknow.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/** class : KnowledgeBase + * shortcut : kb + * + */ +extern picoknow_KnowledgeBase picoknow_newKnowledgeBase(picoos_MemoryManager mm) +{ + picoknow_KnowledgeBase this; + PICODBG_TRACE(("start")); + + this = picoos_allocate(mm,sizeof(*this)); + if (NULL != this) { + PICODBG_TRACE(("allocated KnowledgeBase at address %i with size %i",(picoos_uint32)this,sizeof(*this))); + /* initialize */ + this->next = NULL; + this->id = PICOKNOW_KBID_NULL; + this->base = NULL; + this->size = 0; + this->subObj = NULL; + this->subDeallocate = NULL; + } + return this; +} + +extern void picoknow_disposeKnowledgeBase(picoos_MemoryManager mm, picoknow_KnowledgeBase * this) +{ + picoos_uint8 id; + if (NULL != (*this)) { + id = (*this)->id; + PICODBG_TRACE(("disposing KnowledgeBase id=%i",id)); + /* terminate */ + if ((*this)->subObj != NULL) { + (*this)->subDeallocate((*this),mm); + } + picoos_deallocate(mm,(void**)this); + } +} + +#ifdef __cplusplus +} +#endif + +/* End picoknow.c */ diff --git a/pico/lib/picoknow.h b/pico/lib/picoknow.h new file mode 100644 index 0000000..1444856 --- /dev/null +++ b/pico/lib/picoknow.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picoknow.h + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ +/** + * @addtogroup picoknow + + * Pico knowledge base \n + * +*/ + +#ifndef PICOKNOW_H_ +#define PICOKNOW_H_ + +#include "picodefs.h" +#include "picoos.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +typedef enum picoknow_kb_id { + PICOKNOW_KBID_NULL = 0, + /* base / tpp 1 - 7 */ + PICOKNOW_KBID_TPP_MAIN = 1, + PICOKNOW_KBID_TAB_GRAPHS = 2, + PICOKNOW_KBID_TAB_PHONES = 3, + PICOKNOW_KBID_TAB_POS = 4, + PICOKNOW_KBID_FIXED_IDS = 7, + /* debug */ + PICOKNOW_KBID_DBG = 8, + + /* textana 9 - 32 */ + PICOKNOW_KBID_LEX_MAIN = 9, + PICOKNOW_KBID_DT_POSP = 10, + PICOKNOW_KBID_DT_POSD = 11, + PICOKNOW_KBID_DT_G2P = 12, + PICOKNOW_KBID_FST_WPHO_1 = 13, + PICOKNOW_KBID_FST_WPHO_2 = 14, + PICOKNOW_KBID_FST_WPHO_3 = 15, + PICOKNOW_KBID_FST_WPHO_4 = 16, + PICOKNOW_KBID_FST_WPHO_5 = 17, + PICOKNOW_KBID_DT_PHR = 18, + PICOKNOW_KBID_DT_ACC = 19, + PICOKNOW_KBID_FST_SPHO_1 = 20, + PICOKNOW_KBID_FST_SPHO_2 = 21, + PICOKNOW_KBID_FST_SPHO_3 = 22, + PICOKNOW_KBID_FST_SPHO_4 = 23, + PICOKNOW_KBID_FST_SPHO_5 = 24, + + PICOKNOW_KBID_FST_XSAMPA_PARSE = 25, + PICOKNOW_KBID_FST_SVOXPA_PARSE = 26, + PICOKNOW_KBID_FST_XSAMPA2SVOXPA = 27, + + PICOKNOW_KBID_FST_SPHO_6 = 28, + PICOKNOW_KBID_FST_SPHO_7 = 29, + PICOKNOW_KBID_FST_SPHO_8 = 30, + PICOKNOW_KBID_FST_SPHO_9 = 31, + PICOKNOW_KBID_FST_SPHO_10 = 32, + + + /* siggen 33 - 48 */ + PICOKNOW_KBID_DT_DUR = 34, + PICOKNOW_KBID_DT_LFZ1 = 35, + PICOKNOW_KBID_DT_LFZ2 = 36, + PICOKNOW_KBID_DT_LFZ3 = 37, + PICOKNOW_KBID_DT_LFZ4 = 38, + PICOKNOW_KBID_DT_LFZ5 = 39, + PICOKNOW_KBID_DT_MGC1 = 40, + PICOKNOW_KBID_DT_MGC2 = 41, + PICOKNOW_KBID_DT_MGC3 = 42, + PICOKNOW_KBID_DT_MGC4 = 43, + PICOKNOW_KBID_DT_MGC5 = 44, + PICOKNOW_KBID_PDF_DUR = 45, + PICOKNOW_KBID_PDF_LFZ = 46, + PICOKNOW_KBID_PDF_MGC = 47, + PICOKNOW_KBID_PDF_PHS = 48, + + /* user tpp 49 - 56 */ + PICOKNOW_KBID_TPP_USER_1 = 49, + PICOKNOW_KBID_TPP_USER_2 = 50, + + /* user lex 57 - 63 */ + PICOKNOW_KBID_LEX_USER_1 = 57, + PICOKNOW_KBID_LEX_USER_2 = 58, + + PICOKNOW_KBID_DUMMY = 127 + +} picoknow_kb_id_t; + +#define PICOKNOW_DEFAULT_RESOURCE_NAME (picoos_char *) "__PICO_DEF_RSRC" + +#define PICOKNOW_MAX_NUM_WPHO_FSTS 5 +#define PICOKNOW_MAX_NUM_SPHO_FSTS 10 +#define PICOKNOW_MAX_NUM_ULEX 2 +#define PICOKNOW_MAX_NUM_UTPP 2 + +#define PICOKNOW_KBID_WPHO_ARRAY { \ + PICOKNOW_KBID_FST_WPHO_1, \ + PICOKNOW_KBID_FST_WPHO_2, \ + PICOKNOW_KBID_FST_WPHO_3, \ + PICOKNOW_KBID_FST_WPHO_4, \ + PICOKNOW_KBID_FST_WPHO_5 \ +} + +#define PICOKNOW_KBID_SPHO_ARRAY { \ + PICOKNOW_KBID_FST_SPHO_1, \ + PICOKNOW_KBID_FST_SPHO_2, \ + PICOKNOW_KBID_FST_SPHO_3, \ + PICOKNOW_KBID_FST_SPHO_4, \ + PICOKNOW_KBID_FST_SPHO_5, \ + PICOKNOW_KBID_FST_SPHO_6, \ + PICOKNOW_KBID_FST_SPHO_7, \ + PICOKNOW_KBID_FST_SPHO_8, \ + PICOKNOW_KBID_FST_SPHO_9, \ + PICOKNOW_KBID_FST_SPHO_10 \ +} + +#define PICOKNOW_KBID_ULEX_ARRAY { \ + PICOKNOW_KBID_LEX_USER_1, \ + PICOKNOW_KBID_LEX_USER_2, \ +} + +#define PICOKNOW_KBID_UTPP_ARRAY { \ + PICOKNOW_KBID_TPP_USER_1, \ + PICOKNOW_KBID_TPP_USER_2, \ +} + +/* max size (including NULLC) of descriptive name corresponding to KBID */ +#define PICOKNOW_MAX_KB_NAME_SIZ 16 + +/* maximum number of kbs in one resource */ +#define PICOKNOW_MAX_NUM_RESOURCE_KBS 64 + + +/** class : KnowledgeBase + * shortcut : kb + * + */ +typedef struct picoknow_knowledge_base * picoknow_KnowledgeBase; + +typedef pico_status_t (* picoknow_kbSubDeallocate) (register picoknow_KnowledgeBase this, picoos_MemoryManager mm); + +typedef struct picoknow_knowledge_base { + /* public */ + picoknow_KnowledgeBase next; + picoknow_kb_id_t id; + picoos_uint8 * base; /* start address */ + picoos_uint32 size; /* size */ + + /* protected */ + picoknow_kbSubDeallocate subDeallocate; + void * subObj; +} picoknow_knowledge_base_t; + +extern picoknow_KnowledgeBase picoknow_newKnowledgeBase(picoos_MemoryManager mm); + +extern void picoknow_disposeKnowledgeBase(picoos_MemoryManager mm, picoknow_KnowledgeBase * this); + +#ifdef __cplusplus +} +#endif + + +#endif /*PICOKNOW_H_*/ diff --git a/pico/lib/picokpdf.c b/pico/lib/picokpdf.c new file mode 100644 index 0000000..bbdbec4 --- /dev/null +++ b/pico/lib/picokpdf.c @@ -0,0 +1,381 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picokpdf.c + * + * knowledge handling for pdf + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include "picoos.h" +#include "picodbg.h" +#include "picoknow.h" +#include "picokpdf.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* ************************************************************/ +/* pdf */ +/* ************************************************************/ + +/* + * @addtogroup picokpdf + * + overview: format of knowledge base pdf file + + This is the format for the dur pdf file: + - Numframes: 1 uint16 + - Vecsize: 1 uint8 + - sampperframe: 1 uint8 + - Phonquantlen: 1 uint8 + - Phonquant: Phonquantlen uint8 + - Statequantlen: 1 uint8 + - Statequantlen: Statequantlen uint8 + - And then numframes x vecsize uint8 + + This is the format for mul (mgc and lfz) pdf files: + - numframes: 1 uint16 + - vecsize: 1 uint8 + - numstates: 1 uint8 + - numframesperstate: numstates uint16 + - ceporder: 1 uint8 + - numvuv 1 uint8 + - numdeltas: 1 uint8 + - scmeanpow: 1 uint8 + - maxbigpow: 1 uint8 + - scmeanpowum KPDF_NUMSTREAMS * ceporder uint8 + - scivarpow KPDF_NUMSTREAMS * ceporder uint8 + + And then numframes x vecsize uint8 + +*/ + + +/* ************************************************************/ +/* pdf data defines */ +/* may not be changed with current implementation */ +/* ************************************************************/ + + +#define KPDF_NUMSTREAMS 3 /* coeff, delta, deltadelta */ + + +/* ************************************************************/ +/* pdf loading */ +/* ************************************************************/ + +static pico_status_t kpdfDURInitialize(register picoknow_KnowledgeBase this, + picoos_Common common) { + picokpdf_pdfdur_t *pdfdur; + picoos_uint16 pos; + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + pdfdur = (picokpdf_pdfdur_t *)this->subObj; + + pos = 0; + + pdfdur->numframes = ((picoos_uint16)(this->base[pos+1])) << 8 | + this->base[pos]; + pos += 2; + pdfdur->vecsize = this->base[pos++]; + pdfdur->sampperframe = this->base[pos++]; + pdfdur->phonquantlen = this->base[pos++]; + pdfdur->phonquant = &(this->base[pos]); + pos += pdfdur->phonquantlen; + pdfdur->statequantlen = this->base[pos++]; + pdfdur->statequant = &(this->base[pos]); + pos += pdfdur->statequantlen; + pdfdur->content = &(this->base[pos]); + PICODBG_DEBUG(("numframes %d, vecsize %d, phonquantlen %d, " + "statequantlen %d", pdfdur->numframes, pdfdur->vecsize, + pdfdur->phonquantlen, pdfdur->statequantlen)); + if ((picoos_uint32)(pos + (pdfdur->numframes * pdfdur->vecsize)) != this->size) { + PICODBG_DEBUG(("header-spec size %d, kb-size %d", + pos + (pdfdur->numframes * pdfdur->vecsize), + this->size)); + return picoos_emRaiseException(common->em, PICO_EXC_FILE_CORRUPT, + NULL, NULL); + } + PICODBG_DEBUG(("dur pdf initialized")); + return PICO_OK; +} + +static picoos_uint8 convScaleFactorToBig(picoos_uint8 pow, picoos_uint8 bigpow) +{ + if (pow > 0x0F) { + pow = bigpow + (0xFF - pow + 1); /* take 2's complement of negative pow */ + } else if (bigpow >= pow) { + pow = bigpow - pow; + } else { + /* error: bigpow is smaller than input pow */ + return 0; + } + return pow; +} + +static pico_status_t kpdfMULInitialize(register picoknow_KnowledgeBase this, + picoos_Common common) { + picokpdf_pdfmul_t *pdfmul; + picoos_uint16 pos; + picoos_uint8 scmeanpow, maxbigpow, nummean; + picoos_uint8 i; + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + pdfmul = (picokpdf_pdfmul_t *)this->subObj; + + pos = 0; + + pdfmul->numframes = ((picoos_uint16)(this->base[pos+1])) << 8 | + this->base[pos]; + pos += 2; + pdfmul->vecsize = this->base[pos++]; + pdfmul->numstates = this->base[pos++]; + { + pdfmul->stateoffset[0] = (picoos_uint16) 0; + for (i=1; inumstates; i++) { + pdfmul->stateoffset[i] = pdfmul->stateoffset[i-1] + (this->base[pos] | ((picoos_uint16) this->base[pos+1] << 8)); + pos += 2; + } + pos += 2; /* we don't need the last number if we only need the offset (i.e. how to get to the vector start) */ + } + + pdfmul->ceporder = this->base[pos++]; + pdfmul->numvuv = this->base[pos++]; + pdfmul->numdeltas = this->base[pos++]; + scmeanpow = this->base[pos++]; + maxbigpow = this->base[pos++]; + if (maxbigpow < PICOKPDF_BIG_POW) { + PICODBG_ERROR(("bigpow %i is larger than maxbigpow %i defined in pdf lingware", PICOKPDF_BIG_POW, maxbigpow)); + return picoos_emRaiseException(common->em, PICO_EXC_MAX_NUM_EXCEED,NULL,NULL); + } + pdfmul->bigpow = PICOKPDF_BIG_POW; /* what we have to use is the smaller number! */ + + pdfmul->amplif = this->base[pos++]; + + /* bigpow corrected by scmeanpow, multiply means by 2^meanpow to obtain fixed point representation */ + pdfmul->meanpow = convScaleFactorToBig(scmeanpow, pdfmul->bigpow); + if (0 == pdfmul->meanpow) { + PICODBG_ERROR(("error in convScaleFactorToBig")); + return picoos_emRaiseException(common->em, PICO_EXC_MAX_NUM_EXCEED,NULL,NULL); + } + nummean = 3*pdfmul->ceporder; + + pdfmul->meanpowUm = picoos_allocate(common->mm,nummean*sizeof(picoos_uint8)); + pdfmul->ivarpow = picoos_allocate(common->mm,nummean*sizeof(picoos_uint8)); + if ((NULL == pdfmul->meanpowUm) || (NULL == pdfmul->ivarpow)) { + picoos_deallocate(common->mm,(void *) &(pdfmul->meanpowUm)); + picoos_deallocate(common->mm,(void *) &(pdfmul->ivarpow)); + return picoos_emRaiseException(common->em,PICO_EXC_OUT_OF_MEM,NULL,NULL); + } + + /* read meanpowUm and convert on the fly */ + /* meaning of meanpowUm becomes: multiply means from pdf stream by 2^meanpowUm + * to achieve fixed point scaling by big + */ + for (i=0; imeanpowUm[i] = convScaleFactorToBig(this->base[pos++], pdfmul->bigpow); + } + + /*read ivarpow and convert on the fly */ + for (i=0; iivarpow[i] = convScaleFactorToBig(this->base[pos++], pdfmul->bigpow); + } + + /* check numdeltas */ + if ((pdfmul->numdeltas == 0xFF) && (pdfmul->vecsize != (pdfmul->numvuv + pdfmul->ceporder * 3 * (2+1)))) { + PICODBG_ERROR(("header has inconsistent values for vecsize, ceporder, numvuv, and numdeltas")); + return picoos_emRaiseException(common->em,PICO_EXC_FILE_CORRUPT,NULL,NULL); + } + +/* vecsize: 1 uint8 for vuv + + ceporder short for static means + + numdeltas uint8 and short for sparse delta means + + ceporder*3 uint8 for static and delta inverse variances +*/ + if ((pdfmul->numdeltas != 0xFF) && (pdfmul->vecsize != pdfmul->numvuv+pdfmul->ceporder*2+pdfmul->numdeltas*3+pdfmul->ceporder*3)) { + PICODBG_ERROR(("header has inconsistent values for vecsize, ceporder, numvuv, and numdeltas\n" + "vecsize = %i while numvuv+ceporder*2 + numdeltas*3 + ceporder*3 = %i", + pdfmul->vecsize, pdfmul->numvuv + pdfmul->ceporder*2 + pdfmul->numdeltas * 3 + pdfmul->ceporder * 3)); + return picoos_emRaiseException(common->em,PICO_EXC_FILE_CORRUPT,NULL,NULL); + } + pdfmul->content = &(this->base[pos]); + PICODBG_DEBUG(("numframes %d, vecsize %d, numstates %d, ceporder %d, " + "numvuv %d, numdeltas %d, meanpow %d, bigpow %d", + pdfmul->numframes, pdfmul->vecsize, pdfmul->numstates, + pdfmul->ceporder, pdfmul->numvuv, pdfmul->numdeltas, + pdfmul->meanpow, pdfmul->bigpow)); + if ((picoos_uint32)(pos + (pdfmul->numframes * pdfmul->vecsize)) != this->size) { + PICODBG_DEBUG(("header-spec size %d, kb-size %d", + pos + (pdfmul->numframes * pdfmul->vecsize), + this->size)); + return picoos_emRaiseException(common->em, PICO_EXC_FILE_CORRUPT, + NULL, NULL); + } + PICODBG_DEBUG(("mul pdf initialized")); + return PICO_OK; +} + +static pico_status_t kpdfPHSInitialize(register picoknow_KnowledgeBase this, + picoos_Common common) { + picokpdf_pdfphs_t *pdfphs; + picoos_uint16 pos; + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + pdfphs = (picokpdf_pdfphs_t *)this->subObj; + + pos = 0; + + pdfphs->numvectors = ((picoos_uint16)(this->base[pos+1])) << 8 | + this->base[pos]; + pos += 2; + pdfphs->indexBase = &(this->base[pos]); + pdfphs->contentBase = pdfphs->indexBase + pdfphs->numvectors * sizeof(picoos_uint32); + PICODBG_DEBUG(("phs pdf initialized")); + return PICO_OK; +} + + + +static pico_status_t kpdfMULSubObjDeallocate(register picoknow_KnowledgeBase this, + picoos_MemoryManager mm) { + + + picokpdf_pdfmul_t *pdfmul; + + if ((NULL != this) && (NULL != this->subObj)) { + pdfmul = (picokpdf_pdfmul_t *)this->subObj; + picoos_deallocate(mm,(void *) &(pdfmul->meanpowUm)); + picoos_deallocate(mm,(void *) &(pdfmul->ivarpow)); + picoos_deallocate(mm, (void *) &(this->subObj)); + } + return PICO_OK; +} + +static pico_status_t kpdfDURSubObjDeallocate(register picoknow_KnowledgeBase this, + picoos_MemoryManager mm) { + if (NULL != this) { + picoos_deallocate(mm, (void *) &this->subObj); + } + return PICO_OK; +} + +static pico_status_t kpdfPHSSubObjDeallocate(register picoknow_KnowledgeBase this, + picoos_MemoryManager mm) { + if (NULL != this) { + picoos_deallocate(mm, (void *) &this->subObj); + } + return PICO_OK; +} + +/* we don't offer a specialized constructor for a *KnowledgeBase but + * instead a "specializer" of an allready existing generic + * picoknow_KnowledgeBase */ + +pico_status_t picokpdf_specializePdfKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common, + const picokpdf_kpdftype_t kpdftype) { + pico_status_t status; + + if (NULL == this) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + switch (kpdftype) { + case PICOKPDF_KPDFTYPE_DUR: + this->subDeallocate = kpdfDURSubObjDeallocate; + this->subObj = picoos_allocate(common->mm,sizeof(picokpdf_pdfdur_t)); + if (NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, + NULL, NULL); + } + status = kpdfDURInitialize(this, common); + break; + case PICOKPDF_KPDFTYPE_MUL: + this->subDeallocate = kpdfMULSubObjDeallocate; + this->subObj = picoos_allocate(common->mm,sizeof(picokpdf_pdfmul_t)); + if (NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, + NULL, NULL); + } + status = kpdfMULInitialize(this, common); + break; + case PICOKPDF_KPDFTYPE_PHS: + this->subDeallocate = kpdfPHSSubObjDeallocate; + this->subObj = picoos_allocate(common->mm,sizeof(picokpdf_pdfphs_t)); + if (NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, + NULL, NULL); + } + status = kpdfPHSInitialize(this, common); + break; + + default: + return picoos_emRaiseException(common->em, PICO_ERR_OTHER, + NULL, NULL); + } + + if (status != PICO_OK) { + picoos_deallocate(common->mm, (void *) &this->subObj); + return picoos_emRaiseException(common->em, status, NULL, NULL); + } + return PICO_OK; +} + + +/* ************************************************************/ +/* pdf getPdf* */ +/* ************************************************************/ + +picokpdf_PdfDUR picokpdf_getPdfDUR(picoknow_KnowledgeBase this) { + return ((NULL == this) ? NULL : ((picokpdf_PdfDUR) this->subObj)); +} + +picokpdf_PdfMUL picokpdf_getPdfMUL(picoknow_KnowledgeBase this) { + return ((NULL == this) ? NULL : ((picokpdf_PdfMUL) this->subObj)); +} + +picokpdf_PdfPHS picokpdf_getPdfPHS(picoknow_KnowledgeBase this) { + return ((NULL == this) ? NULL : ((picokpdf_PdfPHS) this->subObj)); +} + + +#ifdef __cplusplus +} +#endif + + +/* end */ diff --git a/pico/lib/picokpdf.h b/pico/lib/picokpdf.h new file mode 100644 index 0000000..f4508a1 --- /dev/null +++ b/pico/lib/picokpdf.h @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picokpdf.h + * + * knowledge handling for pdf + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#ifndef PICOKPDF_H_ +#define PICOKPDF_H_ + +#include "picoos.h" +#include "picoknow.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* ************************************************************/ +/** + * @addtogroup picokpdf + * + Two specialized pdf kb types are provided by this knowledge + handling module: + + - pdf dur: ...kpdf_DUR (for dur) + - pdf mul: ...kpdf_MUL (for lfz and mgc) + - pdf phs: ...kpdf_PHS (for phase) + +*/ +/* ************************************************************/ + + +/* ************************************************************/ +/* defines and functions to create specialized kb, */ +/* to be used by picorsrc only */ +/* ************************************************************/ + +#define PICOKPDF_MAX_NUM_STATES 10 + +#define PICOKPDF_MAX_MUL_LFZ_CEPORDER 1 +#define PICOKPDF_MAX_MUL_MGC_CEPORDER 25 + +/* trade accuracy against computation: more long multiplications. + * Maximum is 15 when invdiag0=(1<<(2*bigpow))/diag0 used + * currently observing instability in mlpg when bigpow >= 14, this needs to be investigated */ + +#define PICOKPDF_BIG_POW 12 + +typedef enum { + PICOKPDF_KPDFTYPE_DUR, + PICOKPDF_KPDFTYPE_MUL, + PICOKPDF_KPDFTYPE_PHS +} picokpdf_kpdftype_t; + +pico_status_t picokpdf_specializePdfKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common, + const picokpdf_kpdftype_t type); + + +/* ************************************************************/ +/* pdf types and get Pdf functions */ +/* ************************************************************/ + +/** object : PdfDur, PdfMUL + * shortcut : kpdf* + * derived from : picoknow_KnowledgeBase + */ + +typedef struct picokpdf_pdfdur *picokpdf_PdfDUR; +typedef struct picokpdf_pdfmul *picokpdf_PdfMUL; +typedef struct picokpdf_pdfphs *picokpdf_PdfPHS; + +/* subobj specific for pdf dur type */ +typedef struct picokpdf_pdfdur { + picoos_uint16 numframes; + picoos_uint8 vecsize; + picoos_uint8 sampperframe; + picoos_uint8 phonquantlen; + picoos_uint8 *phonquant; + picoos_uint8 statequantlen; + picoos_uint8 *statequant; + picoos_uint8 *content; +} picokpdf_pdfdur_t; + +/* subobj specific for pdf mul type */ +typedef struct picokpdf_pdfmul { + picoos_uint16 numframes; + picoos_uint8 vecsize; + picoos_uint8 numstates; + picoos_uint16 stateoffset[PICOKPDF_MAX_NUM_STATES]; /* offset within a phone to find the state ? */ + picoos_uint8 ceporder; + picoos_uint8 numvuv; + picoos_uint8 numdeltas; + picoos_uint8 meanpow; + picoos_uint8 bigpow; + picoos_uint8 amplif; + picoos_uint8 *meanpowUm; /* KPDF_NUMSTREAMS x ceporder values */ + picoos_uint8 *ivarpow; /* KPDF_NUMSTREAMS x ceporder values */ + picoos_uint8 *content; +} picokpdf_pdfmul_t; + +/* subobj specific for pdf phs type */ +typedef struct picokpdf_pdfphs { + picoos_uint16 numvectors; + picoos_uint8 *indexBase; + picoos_uint8 *contentBase; +} picokpdf_pdfphs_t; + +/* return kb pdf for usage in PU */ +picokpdf_PdfDUR picokpdf_getPdfDUR(picoknow_KnowledgeBase this); +picokpdf_PdfMUL picokpdf_getPdfMUL(picoknow_KnowledgeBase this); +picokpdf_PdfPHS picokpdf_getPdfPHS(picoknow_KnowledgeBase this); + + +/* ************************************************************/ +/* PDF DUR functions */ +/* ************************************************************/ + +/* e.g. */ +/*picoos_uint8 picokpdf_pdfDURgetEle(const picokpdf_PdfDUR this, + const picoos_uint16 row, + const picoos_uint16 col, + picoos_uint16 *val); +*/ + +/* ************************************************************/ +/* PDF MUL functions */ +/* ************************************************************/ + +#ifdef __cplusplus +} +#endif + + +#endif /*PICOKPDF_H_*/ diff --git a/pico/lib/picokpr.c b/pico/lib/picokpr.c new file mode 100644 index 0000000..408e564 --- /dev/null +++ b/pico/lib/picokpr.c @@ -0,0 +1,652 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picokpr.c + * + * knowledge handling for text preprocessing + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ +#include "picoos.h" +#include "picodbg.h" +#include "picodata.h" +#include "picoknow.h" +#include "picokpr.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* ************************************************************/ +/* preproc */ +/* ************************************************************/ + +/* + overview: +*/ + + +/* ************************************************************/ +/* preproc data defines */ +/* ************************************************************/ + +#define KPR_STR_SIZE 1 +#define KPR_LEXCAT_SIZE 2 +#define KPR_ATTRVAL_SIZE 4 +#define KPR_OUTITEM_SIZE 7 +#define KPR_TOK_SIZE 16 +#define KPR_PROD_SIZE 12 +#define KPR_CTX_SIZE 12 + +#define KPR_NETNAME_OFFSET 0 +#define KPR_STRARRLEN_OFFSET 4 +#define KPR_LEXCATARRLEN_OFFSET 8 +#define KPR_ATTRVALARRLEN_OFFSET 12 +#define KPR_OUTITEMARRLEN_OFFSET 16 +#define KPR_TOKARRLEN_OFFSET 20 +#define KPR_PRODARRLEN_OFFSET 24 +#define KPR_CTXARRLEN_OFFSET 28 + +#define KPR_ARRAY_START 32 + +#define KPR_MAX_INT32 2147483647 + +#define KPR_STR_OFS 0 + +#define KPR_LEXCAT_OFS 0 + +#define KPR_ATTRVAL_INT_OFS 0 +#define KPR_ATTRVAL_STROFS_OFS 0 +#define KPR_ATTRVAL_PRODOFS_OFS 0 +#define KPR_ATTRVAL_OUTITMOFS_OFS 0 +#define KPR_ATTRVAL_LEXCATOFS_OFS 0 + +#define KPR_OUTITEM_NEXTOFS_OFS 0 +#define KPR_OUTITEM_TYPE_OFS 2 +#define KPR_OUTITEM_STROFS_OFS 3 +#define KPR_OUTITEM_VAL_OFS 3 +#define KPR_OUTITEM_ARGOFS_OFS 3 + +#define KPR_TOK_SETWP_OFS 0 +#define KPR_TOK_SETNP_OFS 4 +#define KPR_TOK_NEXTOFS_OFS 8 +#define KPR_TOK_ALTLOFS_OFS 10 +#define KPR_TOK_ALTROFS_OFS 12 +#define KPR_TOK_ATTRIBOFS_OFS 14 + +#define KPR_PROD_PRODPREFCOST_OFS 0 +#define KPR_PROD_PRODNAMEOFS_OFS 4 +#define KPR_PROD_ATOKOFS_OFS 8 +#define KPR_PROD_ETOKOFS_OFS 10 + +#define KPR_CTX_CTXNAMEOFS_OFS 0 +#define KPR_CTX_NETNAMEOFS_OFS 4 +#define KPR_CTX_PRODNAMEOFS_OFS 8 + +/* ************************************************************/ +/* preproc type and loading */ +/* ************************************************************/ + +/* variable array element types */ +typedef picoos_uint8 picokpr_Str[KPR_STR_SIZE]; +typedef picoos_uint16 picokpr_LexCat2; +typedef picoos_uint8 picokpr_AttrVal[KPR_ATTRVAL_SIZE]; +typedef picoos_uint8 picokpr_OutItem[KPR_OUTITEM_SIZE]; +typedef picoos_uint8 picokpr_Tok[KPR_TOK_SIZE]; +typedef picoos_uint8 picokpr_Prod[KPR_PROD_SIZE]; +typedef picoos_uint8 picokpr_Ctx[KPR_CTX_SIZE]; + +/* variable array types */ +typedef picokpr_Str * picokpr_VarStrArr; +typedef picokpr_LexCat2 * picokpr_VarLexCatArr; +typedef picokpr_AttrVal * picokpr_VarAttrValArr; +typedef picokpr_OutItem * picokpr_VarOutItemArr; +typedef picokpr_Tok * picokpr_VarTokArr; +typedef picokpr_Prod * picokpr_VarProdArr; +typedef picokpr_Ctx * picokpr_VarCtxArr; + +/* ************************************************************/ +/* preproc type and loading */ +/* ************************************************************/ + +/** object : PreprocKnowledgeBase + * shortcut : kpr + * derived from : picoknow_KnowledgeBase + */ + +typedef struct kpr_subobj * kpr_SubObj; + +typedef struct kpr_subobj +{ + picoos_uchar * rNetName; + + picoos_int32 rStrArrLen; + picoos_int32 rLexCatArrLen; + picoos_int32 rAttrValArrLen; + picoos_int32 rOutItemArrLen; + picoos_int32 rTokArrLen; + picoos_int32 rProdArrLen; + picoos_int32 rCtxArrLen; + + picoos_uint8 * rStrArr; + picokpr_LexCat2 * rLexCatArr; + picokpr_AttrVal * rAttrValArr; + picokpr_OutItem * rOutItemArr; + picokpr_Tok * rTokArr; + picokpr_Prod * rProdArr; + picokpr_Ctx * rCtxArr; +} kpr_subobj_t; + + +static picoos_uint32 kpr_getUInt32(picoos_uint8 * p) +{ + return p[0] + 256*p[1] + 256*256*p[2] + 256U*256U*256U*p[3]; +} + + +static pico_status_t kprInitialize(register picoknow_KnowledgeBase this, + picoos_Common common) +{ + picoos_uint32 offset = 0; + kpr_subobj_t * kpr; + + PICODBG_DEBUG(("start")); + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + kpr = (kpr_subobj_t *) this->subObj; + + kpr->rStrArrLen = kpr_getUInt32(&(this->base[KPR_STRARRLEN_OFFSET])); + kpr->rLexCatArrLen = kpr_getUInt32(&(this->base[KPR_LEXCATARRLEN_OFFSET])); + kpr->rAttrValArrLen = kpr_getUInt32(&(this->base[KPR_ATTRVALARRLEN_OFFSET])); + kpr->rOutItemArrLen = kpr_getUInt32(&(this->base[KPR_OUTITEMARRLEN_OFFSET])); + kpr->rTokArrLen = kpr_getUInt32(&(this->base[KPR_TOKARRLEN_OFFSET])); + kpr->rProdArrLen = kpr_getUInt32(&(this->base[KPR_PRODARRLEN_OFFSET])); + kpr->rCtxArrLen = kpr_getUInt32(&(this->base[KPR_CTXARRLEN_OFFSET])); + + offset = KPR_ARRAY_START; + kpr->rStrArr = &(this->base[offset]); + PICODBG_DEBUG(("rStrArr : cs: %i, ss: %i, offset: %i", sizeof(picokpr_Str), KPR_STR_SIZE, offset)); + offset = offset + kpr->rStrArrLen * 1; + + kpr->rLexCatArr = (picokpr_LexCat2 *)&(this->base[offset]); + PICODBG_DEBUG(("rLexCatArr : cs: %i, ss: %i, offset: %i", KPR_LEXCAT_SIZE, sizeof(picokpr_LexCat2), offset)); + offset = offset + kpr->rLexCatArrLen * KPR_LEXCAT_SIZE; + + kpr->rAttrValArr = (picokpr_AttrVal *)&(this->base[offset]); + PICODBG_DEBUG(("rAttrValArr : cs: %i, ss: %i, offset: %i", KPR_ATTRVAL_SIZE, sizeof(picokpr_AttrVal), offset)); + offset = offset + kpr->rAttrValArrLen * KPR_ATTRVAL_SIZE; + + kpr->rOutItemArr = (picokpr_OutItem *)&(this->base[offset]); + PICODBG_DEBUG(("rOutItemArr : cs: %i, ss: %i, offset: %i", KPR_OUTITEM_SIZE, sizeof(picokpr_OutItem), offset)); + offset = offset + kpr->rOutItemArrLen * KPR_OUTITEM_SIZE; + + kpr->rTokArr = (picokpr_Tok *)&(this->base[offset]); + PICODBG_DEBUG(("rTokArr : cs: %i, ss: %i, offset: %i", KPR_TOK_SIZE, sizeof(picokpr_Tok), offset)); + offset = offset + kpr->rTokArrLen * KPR_TOK_SIZE; + + kpr->rProdArr = (picokpr_Prod *)&(this->base[offset]); + PICODBG_DEBUG(("rProdArr : cs: %i, ss: %i, offset: %i", KPR_PROD_SIZE, sizeof(picokpr_Prod), offset)); + offset = offset + kpr->rProdArrLen * KPR_PROD_SIZE; + + kpr->rCtxArr = (picokpr_Ctx *)&(this->base[offset]); + PICODBG_DEBUG(("rCtxArr : cs: %i, ss: %i, offset: %i", KPR_CTX_SIZE, sizeof(picokpr_Ctx), offset)); + offset = offset + kpr->rCtxArrLen * KPR_CTX_SIZE; + + kpr->rNetName = &(kpr->rStrArr[kpr_getUInt32(&(this->base[KPR_NETNAME_OFFSET]))]); + + return PICO_OK; +} + + +static pico_status_t kprSubObjDeallocate(register picoknow_KnowledgeBase this, + picoos_MemoryManager mm) +{ + if (NULL != this) { + picoos_deallocate(mm, (void *) &this->subObj); + } + return PICO_OK; +} + + +/* we don't offer a specialized constructor for a PreprocKnowledgeBase but + * instead a "specializer" of an allready existing generic + * picoknow_KnowledgeBase */ + +pico_status_t picokpr_specializePreprocKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common) +{ + if (NULL == this) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + this->subDeallocate = kprSubObjDeallocate; + this->subObj = picoos_allocate(common->mm, sizeof(kpr_subobj_t)); + if (NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, + NULL, NULL); + } + return kprInitialize(this, common); +} + +/* ************************************************************/ +/* preproc getPreproc */ +/* ************************************************************/ + +picokpr_Preproc picokpr_getPreproc(picoknow_KnowledgeBase this) +{ + if (NULL == this) { + return NULL; + } else { + return (picokpr_Preproc) this->subObj; + } +} + + +/* *****************************************************************************/ +/* knowledge base access routines for strings in StrArr */ +/* *****************************************************************************/ + +extern picokpr_VarStrPtr picokpr_getVarStrPtr(picokpr_Preproc preproc, picokpr_StrArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rStrArr[ofs]); + + return p; +} + +/* *****************************************************************************/ + +extern picoos_bool picokpr_isEqual (picokpr_Preproc preproc, picoos_uchar str[], picoos_int32 len__9, picokpr_StrArrOffset str2) +{ + picokpr_VarStrPtr lstrp; + len__9 = len__9; /*PP 13.10.08 : fix warning "var not used in this function"*/ + lstrp = (picokpr_VarStrPtr)&((kpr_SubObj)preproc)->rStrArr[str2]; + return picoos_strcmp((picoos_char*)lstrp,(picoos_char*)str) == 0; +} + + + +extern picoos_bool picokpr_isEqualHead (picokpr_Preproc preproc, picoos_uchar str[], picoos_int32 len__10, picokpr_StrArrOffset head) +{ + picokpr_VarStrPtr lstrp; + len__10 = len__10; /*PP 13.10.08 : fix warning "var not used in this function"*/ + lstrp = (picokpr_VarStrPtr)&((kpr_SubObj)preproc)->rStrArr[head]; + return (picoos_strstr((picoos_char*)str, (picoos_char*)lstrp) == (picoos_char*)str); +} + + + +extern picoos_bool picokpr_isEqualMid (picokpr_Preproc preproc, picoos_uchar str[], picoos_int32 len__11, picokpr_StrArrOffset mid) +{ + picokpr_VarStrPtr lstrp; + len__11 = len__11; /*PP 13.10.08 : fix warning "var not used in this function"*/ + lstrp = (picokpr_VarStrPtr)(void *) &((kpr_SubObj)preproc)->rStrArr[mid]; + return (picoos_strstr((picoos_char*)str, (picoos_char*)lstrp) != NULL); +} + + + +extern picoos_bool picokpr_isEqualTail (picokpr_Preproc preproc, picoos_uchar str[], picoos_int32 len__12, picokpr_StrArrOffset tail) +{ + picoos_int32 lstart; + picokpr_VarStrPtr lstrp; + len__12 = len__12; /* avoid warning "var not used in this function"*/ + lstrp = (picokpr_VarStrPtr)&((kpr_SubObj)preproc)->rStrArr[tail]; + lstart = picoos_strlen((picoos_char*)str) - picoos_strlen((picoos_char*)lstrp); + if (lstart >= 0) { + return (picoos_strstr((picoos_char*)&(str[lstart]), (picoos_char*)lstrp) != NULL); + } else { + return FALSE; + } +} + +/* *****************************************************************************/ +/* knowledge base access routines for lexical categories in LexCatArr */ +/* *****************************************************************************/ + +extern picokpr_LexCat picokpr_getLexCat(picokpr_Preproc preproc, picokpr_LexCatArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rLexCatArr[ofs]); + + return p[0] + 256*p[1]; +} + +/* *****************************************************************************/ +/* knowledge base access routines for AttrVal fields in AttrValArr */ +/* *****************************************************************************/ + +extern picoos_int32 picokpr_getAttrValArrInt32(picokpr_Preproc preproc, picokpr_AttrValArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rAttrValArr[ofs]); + picoos_uint32 c = p[KPR_ATTRVAL_INT_OFS] + + 256*p[KPR_ATTRVAL_INT_OFS+1] + + 256*256*p[KPR_ATTRVAL_INT_OFS+2] + + 256U*256U*256U*p[KPR_ATTRVAL_INT_OFS+3]; + + if (c > KPR_MAX_INT32) { + return (c - KPR_MAX_INT32) - 1; + } else { + return (((int)c + (int) -(KPR_MAX_INT32)) - 1); + } +} + +/* *****************************************************************************/ +/* knowledge base access routines for AttrVal fields in AttrValArr */ +/* *****************************************************************************/ + +extern picokpr_OutItemArrOffset picokpr_getOutItemNextOfs(picokpr_Preproc preproc, picokpr_OutItemArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rOutItemArr[ofs]); + + return p[KPR_OUTITEM_NEXTOFS_OFS+0] + 256*p[KPR_OUTITEM_NEXTOFS_OFS+1]; +} + + +extern picoos_int32 picokpr_getOutItemType(picokpr_Preproc preproc, picokpr_OutItemArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rOutItemArr[ofs]); + + return p[KPR_OUTITEM_TYPE_OFS+0]; +} + + +extern picokpr_StrArrOffset picokpr_getOutItemStrOfs(picokpr_Preproc preproc, picokpr_OutItemArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rOutItemArr[ofs]); + + return p[KPR_OUTITEM_STROFS_OFS+0] + + 256*p[KPR_OUTITEM_STROFS_OFS+1] + + 256*256*p[KPR_OUTITEM_STROFS_OFS+2] + + 256U*256U*256U*p[KPR_OUTITEM_STROFS_OFS+3]; +} + + +extern picokpr_VarStrPtr picokpr_getOutItemStr(picokpr_Preproc preproc, picokpr_OutItemArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rOutItemArr[ofs]); + picoos_uint32 c = p[KPR_OUTITEM_STROFS_OFS+0] + + 256*p[KPR_OUTITEM_STROFS_OFS+1] + + 256*256*p[KPR_OUTITEM_STROFS_OFS+2] + + 256U*256U*256U*p[KPR_OUTITEM_STROFS_OFS+3]; + + return (picoos_uint8 *)&(((kpr_SubObj)preproc)->rStrArr[c]); +} + +extern picoos_int32 picokpr_getOutItemVal(picokpr_Preproc preproc, picokpr_OutItemArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rOutItemArr[ofs]); + picoos_uint32 c = p[KPR_OUTITEM_VAL_OFS+0] + + 256*p[KPR_OUTITEM_VAL_OFS+1] + + 256*256*p[KPR_OUTITEM_VAL_OFS+2] + + 256U*256U*256U*p[KPR_OUTITEM_VAL_OFS+3]; + + if (c > KPR_MAX_INT32) { + return (c - KPR_MAX_INT32) - 1; + } else { + return (((int)c + (int) -(KPR_MAX_INT32)) - 1); + } +} + + +extern picokpr_OutItemArrOffset picokpr_getOutItemArgOfs(picokpr_Preproc preproc, picokpr_OutItemArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rOutItemArr[ofs]); + + return p[KPR_OUTITEM_ARGOFS_OFS+0] + + 256*p[KPR_OUTITEM_ARGOFS_OFS+1] + + 256*256*p[KPR_OUTITEM_ARGOFS_OFS+2] + + 256U*256U*256U*p[KPR_OUTITEM_ARGOFS_OFS+3]; +} + + +/* *****************************************************************************/ +/* knowledge base access routines for tokens in TokArr */ +/* *****************************************************************************/ + +extern picokpr_TokSetNP picokpr_getTokSetNP(picokpr_Preproc preproc, picokpr_TokArrOffset ofs) +{ + picoos_uint32 c/*, b*/; + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rTokArr[ofs]) + KPR_TOK_SETNP_OFS; + /*picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rTokArr[ofs]);*/ + picoos_uint32 p0, p1, p2, p3; + + p0 = *(p++); + p1 = *(p++); + p2 = *(p++); + p3 = *p; + + c = p0 + (p1<<8) + (p2<<16) + (p3<<24); + + return c; + + /* + c = p[KPR_TOK_SETNP_OFS+0] + + 256*p[KPR_TOK_SETNP_OFS+1] + + 256*256*p[KPR_TOK_SETNP_OFS+2] + + 256U*256U*256U*p[KPR_TOK_SETNP_OFS+3]; + + b = 0; + i = 0; + while ((i <= 31) && (c > 0)) { + if (c % 2 == 1) { + b |= (1<rTokArr[ofs]);*/ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rTokArr[ofs]) + KPR_TOK_SETWP_OFS; + picoos_uint32 p0, p1, p2, p3; + + p0 = *(p++); + p1 = *(p++); + p2 = *(p++); + p3 = *p; + + c = p0 + (p1<<8) + (p2<<16) + (p3<<24); + return c; + + /* + c = p[KPR_TOK_SETWP_OFS+0] + + 256*p[KPR_TOK_SETWP_OFS+1] + + 256*256*p[KPR_TOK_SETWP_OFS+2] + + 256U*256U*256U*p[KPR_TOK_SETWP_OFS+3]; + + b = 0; + i = 0; + while ((i <= 31) && (c > 0)) { + if (c % 2 == 1) { + b |= (1<rTokArr[ofs]); + + return p[KPR_TOK_NEXTOFS_OFS+0] + 256*p[KPR_TOK_NEXTOFS_OFS+1]; +} + + +extern picokpr_TokArrOffset picokpr_getTokAltLOfs(picokpr_Preproc preproc, picokpr_TokArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rTokArr[ofs]) + KPR_TOK_ALTLOFS_OFS; + picokpr_TokArrOffset c = *p++; + return c + 256**p; + + /*picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rTokArr[ofs]); + + return p[KPR_TOK_ALTLOFS_OFS+0] + 256*p[KPR_TOK_ALTLOFS_OFS+1]; + */ +} + + +extern picokpr_TokArrOffset picokpr_getTokAltROfs(picokpr_Preproc preproc, picokpr_TokArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rTokArr[ofs]) + KPR_TOK_ALTROFS_OFS; + picokpr_TokArrOffset c = *p++; + return c + 256**p; + + /*picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rTokArr[ofs]); + + return p[KPR_TOK_ALTROFS_OFS+0] + 256*p[KPR_TOK_ALTROFS_OFS+1];*/ +} + + +extern picokpr_AttrValArrOffset picokpr_getTokAttribOfs(picokpr_Preproc preproc, picokpr_TokArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rTokArr[ofs]); + + return p[KPR_TOK_ATTRIBOFS_OFS+0] + 256*p[KPR_TOK_ATTRIBOFS_OFS+1]; +} + +/* *****************************************************************************/ +/* knowledge base access routines for productions in ProdArr */ +/* *****************************************************************************/ + +extern picoos_int32 picokpr_getProdArrLen(picokpr_Preproc preproc) +{ + return ((kpr_SubObj)preproc)->rProdArrLen; +} + +extern picoos_int32 picokpr_getProdPrefCost(picokpr_Preproc preproc, picokpr_ProdArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rProdArr[ofs]); + picoos_uint32 c = p[KPR_PROD_PRODPREFCOST_OFS+0] + + 256*p[KPR_PROD_PRODPREFCOST_OFS+1] + + 256*256*p[KPR_PROD_PRODPREFCOST_OFS+2] + + 256U*256U*256U*p[KPR_PROD_PRODPREFCOST_OFS+3]; + + + if (c > KPR_MAX_INT32) { + return (c - KPR_MAX_INT32) - 1; + } else { + return (((int)c + (int) -(KPR_MAX_INT32)) - 1); + } +} + + +extern picokpr_StrArrOffset picokpr_getProdNameOfs(picokpr_Preproc preproc, picokpr_ProdArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rProdArr[ofs]); + + return p[KPR_PROD_PRODNAMEOFS_OFS+0] + + 256*p[KPR_PROD_PRODNAMEOFS_OFS+1] + + 256*256*p[KPR_PROD_PRODNAMEOFS_OFS+2] + + 256U*256U*256U*p[KPR_PROD_PRODNAMEOFS_OFS+3]; + +} + + +extern picokpr_TokArrOffset picokpr_getProdATokOfs(picokpr_Preproc preproc, picokpr_ProdArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rProdArr[ofs]); + + return p[KPR_PROD_ATOKOFS_OFS+0] + 256*p[KPR_PROD_ATOKOFS_OFS+1]; +} + + +extern picokpr_TokArrOffset picokpr_getProdETokOfs(picokpr_Preproc preproc, picokpr_ProdArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rProdArr[ofs]); + + return p[KPR_PROD_ETOKOFS_OFS+0] + 256*p[KPR_PROD_ETOKOFS_OFS+1]; +} + +/* *****************************************************************************/ +/* knowledge base access routines for contexts in CtxArr */ +/* *****************************************************************************/ + +extern picoos_int32 picokpr_getCtxArrLen(picokpr_Preproc preproc) +{ + return ((kpr_SubObj)preproc)->rCtxArrLen; +} + +extern picokpr_StrArrOffset picokpr_getCtxCtxNameOfs(picokpr_Preproc preproc, picokpr_CtxArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rCtxArr[ofs]); + + return p[KPR_CTX_CTXNAMEOFS_OFS+0] + + 256*p[KPR_CTX_CTXNAMEOFS_OFS+1] + + 256*256*p[KPR_CTX_CTXNAMEOFS_OFS+2] + + 256U*256U*256U*p[KPR_CTX_CTXNAMEOFS_OFS+3]; +} + + +extern picokpr_StrArrOffset picokpr_getCtxNetNameOfs(picokpr_Preproc preproc, picokpr_CtxArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rCtxArr[ofs]); + + return p[KPR_CTX_NETNAMEOFS_OFS+0] + + 256*p[KPR_CTX_NETNAMEOFS_OFS+1] + + 256*256*p[KPR_CTX_NETNAMEOFS_OFS+2] + + 256U*256U*256U*p[KPR_CTX_NETNAMEOFS_OFS+3]; +} + + +extern picokpr_StrArrOffset picokpr_getCtxProdNameOfs(picokpr_Preproc preproc, picokpr_CtxArrOffset ofs) +{ + picoos_uint8 * p = (picoos_uint8 *)&(((kpr_SubObj)preproc)->rCtxArr[ofs]); + + return p[KPR_CTX_PRODNAMEOFS_OFS+0] + + 256*p[KPR_CTX_PRODNAMEOFS_OFS+1] + + 256*256*p[KPR_CTX_PRODNAMEOFS_OFS+2] + + 256U*256U*256U*p[KPR_CTX_PRODNAMEOFS_OFS+3]; +} + +/* *****************************************************************************/ +/* knowledge base access routines for networks */ +/* *****************************************************************************/ + +extern picokpr_VarStrPtr picokpr_getPreprocNetName(picokpr_Preproc preproc) +{ + return ((kpr_SubObj)preproc)->rNetName; +} + + +#ifdef __cplusplus +} +#endif + + +/* end */ diff --git a/pico/lib/picokpr.h b/pico/lib/picokpr.h new file mode 100644 index 0000000..0532b49 --- /dev/null +++ b/pico/lib/picokpr.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picokpr.h + * + * knowledge handling for text preprocessing + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ +/** + * @addtogroup picokpr + + * Knowledge handling for text preprocessing \n + * +*/ + +#ifndef PICOKPR_H_ +#define PICOKPR_H_ + +#include "picoos.h" +#include "picoknow.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* ************************************************************/ +/* function to create specialized kb, */ +/* to be used by picorsrc only */ +/* ************************************************************/ + +pico_status_t picokpr_specializePreprocKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common); + + +/* ************************************************************/ +/* preproc type and getPreproc function */ +/* ************************************************************/ + +/* maximal array length in preproc knowledge */ +#define NPPMaxStrArrLen 100000000 +#define NPPMaxLexCatArrLen 65536 +#define NPPMaxAttrValLen 65536 +#define NPPMaxOutItemArrLen 65536 +#define NPPMaxTokArrLen 65536 +#define NPPMaxProdArrLen 65536 +#define NPPMaxCtxArrLen 65536 + +/* array offset types */ +typedef picoos_uint32 picokpr_StrArrOffset; +typedef picoos_uint16 picokpr_LexCatArrOffset; +typedef picoos_uint16 picokpr_AttrValArrOffset; +typedef picoos_uint16 picokpr_OutItemArrOffset; +typedef picoos_uint16 picokpr_TokArrOffset; +typedef picoos_uint16 picokpr_ProdArrOffset; +typedef picoos_uint16 picokpr_CtxArrOffset; + +typedef picoos_uchar * picokpr_VarStrPtr; + +typedef picoos_int16 picokpr_LexCat; +typedef picoos_uint32 picokpr_TokSetNP; +typedef picoos_uint32 picokpr_TokSetWP; + +/* preproc types */ +typedef struct picokpr_preproc * picokpr_Preproc; + +/* return kb preproc for usage in PU */ +picokpr_Preproc picokpr_getPreproc(picoknow_KnowledgeBase this); + + +/* *****************************************************************************/ +/* access routines */ +/* *****************************************************************************/ + +/* knowledge base access routines for strings in StrArr */ +extern picokpr_VarStrPtr picokpr_getVarStrPtr(picokpr_Preproc preproc, picokpr_StrArrOffset ofs); +extern picoos_bool picokpr_isEqual (picokpr_Preproc preproc, picoos_uchar str[], picoos_int32 len__9, picokpr_StrArrOffset str2); +extern picoos_bool picokpr_isEqualHead (picokpr_Preproc preproc, picoos_uchar str[], picoos_int32 len__10, picokpr_StrArrOffset head); +extern picoos_bool picokpr_isEqualMid (picokpr_Preproc preproc, picoos_uchar str[], picoos_int32 len__11, picokpr_StrArrOffset mid); +extern picoos_bool picokpr_isEqualTail (picokpr_Preproc preproc, picoos_uchar str[], picoos_int32 len__12, picokpr_StrArrOffset tail); + +/* knowledge base access routines for lexical categories in LexCatArr */ +extern picokpr_LexCat picokpr_getLexCat(picokpr_Preproc preproc, picokpr_LexCatArrOffset ofs); + +/* knowledge base access routines for AttrVal fields in AttrValArr */ +extern picoos_int32 picokpr_getAttrValArrInt32(picokpr_Preproc preproc, picokpr_AttrValArrOffset ofs); + +/* knowledge base access routines for out items fields in OutItemArr */ +extern picokpr_StrArrOffset picokpr_getOutItemStrOfs(picokpr_Preproc preproc, picokpr_OutItemArrOffset ofs); +extern picokpr_VarStrPtr picokpr_getOutItemStr(picokpr_Preproc preproc, picokpr_OutItemArrOffset ofs); +extern picoos_int32 picokpr_getOutItemType(picokpr_Preproc preproc, picokpr_OutItemArrOffset ofs); +extern picoos_int32 picokpr_getOutItemVal(picokpr_Preproc preproc, picokpr_OutItemArrOffset ofs); +extern picokpr_OutItemArrOffset picokpr_getOutItemArgOfs(picokpr_Preproc preproc, picokpr_OutItemArrOffset ofs); +extern picokpr_OutItemArrOffset picokpr_getOutItemNextOfs(picokpr_Preproc preproc, picokpr_OutItemArrOffset ofs); + +/* knowledge base access routines for tokens in TokArr */ +extern picokpr_TokSetNP picokpr_getTokSetNP(picokpr_Preproc preproc, picokpr_TokArrOffset ofs); +extern picokpr_TokSetWP picokpr_getTokSetWP(picokpr_Preproc preproc, picokpr_TokArrOffset ofs); +extern picokpr_TokArrOffset picokpr_getTokNextOfs(picokpr_Preproc preproc, picokpr_TokArrOffset ofs); +extern picokpr_TokArrOffset picokpr_getTokAltLOfs(picokpr_Preproc preproc, picokpr_TokArrOffset ofs); +extern picokpr_TokArrOffset picokpr_getTokAltROfs(picokpr_Preproc preproc, picokpr_TokArrOffset ofs); +extern picokpr_AttrValArrOffset picokpr_getTokAttribOfs(picokpr_Preproc preproc, picokpr_TokArrOffset ofs); + +/* knowledge base access routines for productions in ProdArr */ +extern picoos_int32 picokpr_getProdArrLen(picokpr_Preproc preproc); +extern picoos_int32 picokpr_getProdPrefCost(picokpr_Preproc preproc, picokpr_ProdArrOffset ofs); +extern picokpr_StrArrOffset picokpr_getProdNameOfs(picokpr_Preproc preproc, picokpr_ProdArrOffset ofs); +extern picokpr_TokArrOffset picokpr_getProdATokOfs(picokpr_Preproc preproc, picokpr_ProdArrOffset ofs); +extern picokpr_TokArrOffset picokpr_getProdETokOfs(picokpr_Preproc preproc, picokpr_ProdArrOffset ofs); + +/* knowledge base access routines for contexts in CtxArr */ +extern picoos_int32 picokpr_getCtxArrLen(picokpr_Preproc preproc); +extern picokpr_StrArrOffset picokpr_getCtxCtxNameOfs(picokpr_Preproc preproc, picokpr_CtxArrOffset ofs); +extern picokpr_StrArrOffset picokpr_getCtxNetNameOfs(picokpr_Preproc preproc, picokpr_CtxArrOffset ofs); +extern picokpr_StrArrOffset picokpr_getCtxProdNameOfs(picokpr_Preproc preproc, picokpr_CtxArrOffset ofs); + +/* knowledge base access routines for preprocs */ +extern picokpr_VarStrPtr picokpr_getPreprocNetName(picokpr_Preproc preproc); + +#ifdef __cplusplus +} +#endif + + +#endif /*PICOKPR_H_*/ diff --git a/pico/lib/picoktab.c b/pico/lib/picoktab.c new file mode 100644 index 0000000..ca8b470 --- /dev/null +++ b/pico/lib/picoktab.c @@ -0,0 +1,1118 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picoktab.c + * + * symbol tables needed at runtime + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include "picoos.h" +#include "picodbg.h" +#include "picoknow.h" +#include "picobase.h" +#include "picoktab.h" +#include "picodata.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/** @todo : the following would be better part of a knowledge base. + * Make sure it is consistent with the phoneme symbol table used in the lingware */ + +/* PLANE_PHONEMES */ + +/* PLANE_POS */ + +/* PLANE_PB_STRENGTHS */ + +/* PLANE_ACCENTS */ + +/* PLANE_INTERN */ +#define PICOKTAB_TMPID_PHONSTART '\x26' /* 38 '&' */ +#define PICOKTAB_TMPID_PHONTERM '\x23' /* 35 '#' */ + + +/* ************************************************************/ +/* fixed ids */ +/* ************************************************************/ + + +static pico_status_t ktabIdsInitialize(register picoknow_KnowledgeBase this, + picoos_Common common) +{ + picoktab_FixedIds ids; + + PICODBG_DEBUG(("start")); + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + ids = (picoktab_FixedIds) this->subObj; + + ids->phonStartId = PICOKTAB_TMPID_PHONSTART; + ids->phonTermId = PICOKTAB_TMPID_PHONTERM; + return PICO_OK; +} + + +static pico_status_t ktabIdsSubObjDeallocate(register picoknow_KnowledgeBase this, + picoos_MemoryManager mm) +{ + if (NULL != this) { + picoos_deallocate(mm, (void *) &this->subObj); + } + return PICO_OK; +} + +pico_status_t picoktab_specializeIdsKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common) +{ + if (NULL == this) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + this->subDeallocate = ktabIdsSubObjDeallocate; + this->subObj = picoos_allocate(common->mm, sizeof(picoktab_fixed_ids_t)); + if (NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, + NULL, NULL); + } + return ktabIdsInitialize(this, common); +} + +picoktab_FixedIds picoktab_getFixedIds(picoknow_KnowledgeBase this) +{ + return ((NULL == this) ? NULL : ((picoktab_FixedIds) this->subObj)); +} + + +picoktab_FixedIds picoktab_newFixedIds(picoos_MemoryManager mm) +{ + picoktab_FixedIds this = (picoktab_FixedIds) picoos_allocate(mm,sizeof(*this)); + if (NULL != this) { + /* initialize */ + } + return this; +} + + +void picoktab_disposeFixedIds(picoos_MemoryManager mm, picoktab_FixedIds * this) +{ + if (NULL != (*this)) { + /* terminate */ + picoos_deallocate(mm,(void *)this); + } +} + + + +/* ************************************************************/ +/* Graphs */ +/* ************************************************************/ + +/* overview binary file format for graphs kb: + + graphs-kb = NROFSENTRIES SIZEOFSENTRY ofstable graphs + + NROFSENTRIES : 2 bytes, number of entries in offset table + SIZEOFSENTRY : 1 byte, size of one entry in offset table + + ofstable = {OFFSET}=NROFSENTRIES (contains NROFSENTRIES entries of OFFSET) + + OFFSET: SIZEOFSENTRY bytes, offset to baseaddress of graphs-kb to entry in graphs + + graphs = {graph}=NROFSENTRIES (contains NROFSENTRIES entries of graph) + + graph = PROPSET FROM TO [TOKENTYPE] [TOKENSUBTYPE] [VALUE] [LOWERCASE] [GRAPHSUBS1] [GRAPHSUBS2] + + FROM : 1..4 unsigned bytes, UTF8 character without terminating 0 + TO : 1..4 unsigned bytes, UTF8 character without terminating 0 + PROPSET : 1 unsigned byte, least significant bit : has TO field + next bit : has TOKENTYPE + next bit : has TOKENSUBTYPE + next bit : has VALUE + next bit : has LOWERCASE + next bit : has GRAPHSUBS1 + next bit : has GRAPHSUBS2 + next bit : has PUNC + + TOKENTYPE : 1 unsigned byte + TOKENSUBTYPE : 1 unsigned byte + VALUE : 1 unsigned byte + LOWERCASE : 1..4 unsigned bytes, UTF8 character without terminating 0 + GRAPHSUBS1 : 1..4 unsigned bytes, UTF8 character without terminating 0 + GRAPHSUBS2 : 1..4 unsigned bytes, UTF8 character without terminating 0 + PUNC : 1 unsigned byte +*/ + +static picoos_uint32 ktab_propOffset (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uint32 prop); + +#define KTAB_START_GRAPHS_NR_OFFSET 0 +#define KTAB_START_GRAPHS_SIZE_OFFSET 2 +#define KTAB_START_GRAPHS_OFFSET_TABLE 3 +#define KTAB_START_GRAPHS_GRAPH_TABLE 0 + +/* bitmasks to extract the grapheme properties info from the property set */ +#define KTAB_GRAPH_PROPSET_TO ((picoos_uint8)'\x01') +#define KTAB_GRAPH_PROPSET_TOKENTYPE ((picoos_uint8)'\x02') +#define KTAB_GRAPH_PROPSET_TOKENSUBTYPE ((picoos_uint8)'\x04') +#define KTAB_GRAPH_PROPSET_VALUE ((picoos_uint8)'\x08') +#define KTAB_GRAPH_PROPSET_LOWERCASE ((picoos_uint8)'\x010') +#define KTAB_GRAPH_PROPSET_GRAPHSUBS1 ((picoos_uint8)'\x020') +#define KTAB_GRAPH_PROPSET_GRAPHSUBS2 ((picoos_uint8)'\x040') +#define KTAB_GRAPH_PROPSET_PUNCT ((picoos_uint8)'\x080') + + +typedef struct ktabgraphs_subobj *ktabgraphs_SubObj; + +typedef struct ktabgraphs_subobj { + picoos_uint16 nrOffset; + picoos_uint16 sizeOffset; + + picoos_uint8 * offsetTable; + picoos_uint8 * graphTable; +} ktabgraphs_subobj_t; + + + +static pico_status_t ktabGraphsInitialize(register picoknow_KnowledgeBase this, + picoos_Common common) { + ktabgraphs_subobj_t * ktabgraphs; + + PICODBG_DEBUG(("start")); + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + ktabgraphs = (ktabgraphs_subobj_t *) this->subObj; + ktabgraphs->nrOffset = ((int)(this->base[KTAB_START_GRAPHS_NR_OFFSET])) + 256*(int)(this->base[KTAB_START_GRAPHS_NR_OFFSET+1]); + ktabgraphs->sizeOffset = (int)(this->base[KTAB_START_GRAPHS_SIZE_OFFSET]); + ktabgraphs->offsetTable = &(this->base[KTAB_START_GRAPHS_OFFSET_TABLE]); + ktabgraphs->graphTable = &(this->base[KTAB_START_GRAPHS_GRAPH_TABLE]); + return PICO_OK; +} + +static pico_status_t ktabGraphsSubObjDeallocate(register picoknow_KnowledgeBase this, + picoos_MemoryManager mm) { + if (NULL != this) { + picoos_deallocate(mm, (void *) &this->subObj); + } + return PICO_OK; +} + + +pico_status_t picoktab_specializeGraphsKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common) { + if (NULL == this) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + this->subDeallocate = ktabGraphsSubObjDeallocate; + this->subObj = picoos_allocate(common->mm, sizeof(ktabgraphs_subobj_t)); + if (NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, + NULL, NULL); + } + return ktabGraphsInitialize(this, common); +} + + +picoktab_Graphs picoktab_getGraphs(picoknow_KnowledgeBase this) { + if (NULL == this) { + return NULL; + } else { + return (picoktab_Graphs) this->subObj; + } +} + + +/* Graphs methods */ + +picoos_uint8 picoktab_hasVowellikeProp(const picoktab_Graphs this, + const picoos_uint8 *graph, + const picoos_uint8 graphlenmax) { + + picoos_uint8 ui8App; + picoos_uint32 graphsOffset; + ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this; + + ui8App = graphlenmax; /* avoid warning "var not used in this function"*/ + + graphsOffset = picoktab_graphOffset (this, (picoos_uchar *)graph); + return g->graphTable[graphsOffset + ktab_propOffset (this, graphsOffset, KTAB_GRAPH_PROPSET_TOKENTYPE)] == PICODATA_ITEMINFO1_TOKTYPE_LETTERV; +} + + +static void ktab_getStrProp (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uint32 propOffset, picoos_uchar * str) +{ + ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this; + picoos_uint32 i, l; + + i = 0; + l = picobase_det_utf8_length(g->graphTable[graphsOffset+propOffset]); + while (igraphTable[graphsOffset+propOffset+i]; + i++; + } + str[l] = 0; +} + + +static picoos_uint32 ktab_propOffset(const picoktab_Graphs this, + picoos_uint32 graphsOffset, picoos_uint32 prop) +/* Returns offset of property 'prop' inside the graph with offset 'graphsOffset' in graphs table; + If the property is found, a value > 0 is returned otherwise 0 */ +{ + picoos_uint32 n = 0; + ktabgraphs_subobj_t * g = (ktabgraphs_SubObj) this; + + if ((g->graphTable[graphsOffset] & prop) == prop) { + n = n + 1; /* overread PROPSET field */ + n = n + picobase_det_utf8_length(g->graphTable[graphsOffset+n]); /* overread FROM field */ + if (prop > KTAB_GRAPH_PROPSET_TO) { + if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_TO) + == KTAB_GRAPH_PROPSET_TO) { + n = n + picobase_det_utf8_length(g->graphTable[graphsOffset+n]); /* overread TO field */ + } + } else { + return n; + } + if (prop > KTAB_GRAPH_PROPSET_TOKENTYPE) { + if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_TOKENTYPE) + == KTAB_GRAPH_PROPSET_TOKENTYPE) { + n = n + 1; /* overread TOKENTYPE field */ + } + } else { + return n; + } + if (prop > KTAB_GRAPH_PROPSET_TOKENSUBTYPE) { + if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_TOKENSUBTYPE) + == KTAB_GRAPH_PROPSET_TOKENSUBTYPE) { + n = n + 1; /* overread stokentype field */ + } + } else { + return n; + } + if (prop > KTAB_GRAPH_PROPSET_VALUE) { + if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_VALUE) + == KTAB_GRAPH_PROPSET_VALUE) { + n = n + 1; /* overread value field */ + } + } else { + return n; + } + if (prop > KTAB_GRAPH_PROPSET_LOWERCASE) { + if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_LOWERCASE) + == KTAB_GRAPH_PROPSET_LOWERCASE) { + n = n + picobase_det_utf8_length(g->graphTable[graphsOffset+n]); /* overread lowercase field */ + } + } else { + return n; + } + if (prop > KTAB_GRAPH_PROPSET_GRAPHSUBS1) { + if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_GRAPHSUBS1) + == KTAB_GRAPH_PROPSET_GRAPHSUBS1) { + n = n + picobase_det_utf8_length(g->graphTable[graphsOffset+n]); /* overread graphsubs1 field */ + } + } else { + return n; + } + if (prop > KTAB_GRAPH_PROPSET_GRAPHSUBS2) { + if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_GRAPHSUBS2) + == KTAB_GRAPH_PROPSET_GRAPHSUBS2) { + n = n + picobase_det_utf8_length(g->graphTable[graphsOffset+n]); /* overread graphsubs2 field */ + } + } else { + return n; + } + if (prop > KTAB_GRAPH_PROPSET_PUNCT) { + if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_PUNCT) + == KTAB_GRAPH_PROPSET_PUNCT) { + n = n + 1; /* overread value field */ + } + } else { + return n; + } + } + + return n; +} + + +picoos_uint32 picoktab_graphOffset (const picoktab_Graphs this, picoos_uchar * utf8graph) +{ ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this; + picoos_int32 a, b, m; + picoos_uint32 graphsOffset; + picoos_uint32 propOffset; + picobase_utf8char from; + picobase_utf8char to; + picoos_bool utfGEfrom; + picoos_bool utfLEto; + + if (g->nrOffset > 0) { + a = 0; + b = g->nrOffset-1; + do { + m = (a+b) / 2; + + /* get offset to graph[m] */ + if (g->sizeOffset == 1) { + graphsOffset = g->offsetTable[g->sizeOffset*m]; + } + else { + graphsOffset = g->offsetTable[g->sizeOffset*m ] + + 256*g->offsetTable[g->sizeOffset*m + 1]; + /* PICODBG_DEBUG(("picoktab_graphOffset: %i %i %i %i", m, g->offsetTable[g->sizeOffset*m], g->offsetTable[g->sizeOffset*m + 1], graphsOffset)); + */ + } + + /* get FROM and TO field of graph[m] */ + ktab_getStrProp(this, graphsOffset, 1, from); + propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_TO); + if (propOffset > 0) { + ktab_getStrProp(this, graphsOffset, propOffset, to); + } + else { + picoos_strcpy((picoos_char *)to, (picoos_char *)from); + } + + /* PICODBG_DEBUG(("picoktab_graphOffset: %i %i %i '%s' '%s' '%s'", a, m, b, from, utf8graph, to)); + */ + utfGEfrom = picoos_strcmp((picoos_char *)utf8graph, (picoos_char *)from) >= 0; + utfLEto = picoos_strcmp((picoos_char *)utf8graph, (picoos_char *)to) <= 0; + + if (utfGEfrom && utfLEto) { + /* PICODBG_DEBUG(("picoktab_graphOffset: utf char '%s' found", utf8graph)); + */ + return graphsOffset; + } + if (!utfGEfrom) { + b = m-1; + } + else if (!utfLEto) { + a = m+1; + } + } while (a<=b); + } + PICODBG_DEBUG(("picoktab_graphOffset: utf char '%s' not found", utf8graph)); + return 0; +} + + + + +picoos_bool picoktab_getIntPropTokenType (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uint8 * stokenType) +{ + picoos_uint32 propOffset; + ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this; + + propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_TOKENTYPE); + if (propOffset > 0) { + *stokenType = (picoos_uint8)(g->graphTable[graphsOffset+propOffset]); + return TRUE; + } + else { + return FALSE; + } +} + + +picoos_bool picoktab_getIntPropTokenSubType (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_int8 * stokenSubType) +{ + picoos_uint32 propOffset; + ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this; + + propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_TOKENSUBTYPE); + if (propOffset > 0) { + *stokenSubType = (picoos_int8)(g->graphTable[graphsOffset+propOffset]); + return TRUE; + } + else { + return FALSE; + } +} + +picoos_bool picoktab_getIntPropValue (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uint32 * value) +{ + picoos_uint32 propOffset; + ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this; + + propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_VALUE); + if (propOffset > 0) { + *value = (picoos_uint32)(g->graphTable[graphsOffset+propOffset]); + return TRUE; + } + else { + return FALSE; + } +} + + +picoos_bool picoktab_getIntPropPunct (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uint8 * info1, picoos_uint8 * info2) +{ + picoos_uint32 propOffset; + ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this; + + propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_PUNCT); + if (propOffset > 0) { + if (g->graphTable[graphsOffset+propOffset] == 2) { + *info1 = PICODATA_ITEMINFO1_PUNC_SENTEND; + } + else { + *info1 = PICODATA_ITEMINFO1_PUNC_PHRASEEND; + } + if (g->graphTable[graphsOffset+1] == '.') { + *info2 = PICODATA_ITEMINFO2_PUNC_SENT_T; + } + else if (g->graphTable[graphsOffset+1] == '?') { + *info2 = PICODATA_ITEMINFO2_PUNC_SENT_Q; + } + else if (g->graphTable[graphsOffset+1] == '!') { + *info2 = PICODATA_ITEMINFO2_PUNC_SENT_E; + } + else { + *info2 = PICODATA_ITEMINFO2_PUNC_PHRASE; + } + return TRUE; + } + else { + return FALSE; + } +} + + +picoos_bool picoktab_getStrPropLowercase (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uchar * lowercase) +{ + picoos_uint32 propOffset; + + propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_LOWERCASE); + if (propOffset > 0) { + ktab_getStrProp(this, graphsOffset, propOffset, lowercase); + return TRUE; + } + else { + return FALSE; + } +} + + +picoos_bool picoktab_getStrPropGraphsubs1 (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uchar * graphsubs1) +{ + picoos_uint32 propOffset; + + propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_GRAPHSUBS1); + if (propOffset > 0) { + ktab_getStrProp(this, graphsOffset, propOffset, graphsubs1); + return TRUE; + } + else { + return FALSE; + } +} + + +picoos_bool picoktab_getStrPropGraphsubs2 (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uchar * graphsubs2) +{ + picoos_uint32 propOffset; + + propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_GRAPHSUBS2); + if (propOffset > 0) { + ktab_getStrProp(this, graphsOffset, propOffset, graphsubs2); + return TRUE; + } + else { + return FALSE; + } +} +/* *****************************************************************/ +/* used for tools */ + +static void ktab_getUtf8 (picoos_uchar ** pos, picoos_uchar * to) +{ + picoos_uint32 l; + l = picobase_det_utf8_length(**pos); + while (l>0) { + *(to++) = *((*pos)++); + l--; + } + *to = 0; +} + +picoos_uint16 picoktab_graphsGetNumEntries(const picoktab_Graphs this) +{ + ktabgraphs_subobj_t * g = (ktabgraphs_SubObj) this; + return g->nrOffset; +} + +void picoktab_graphsGetGraphInfo(const picoktab_Graphs this, + picoos_uint16 graphIndex, picoos_uchar * from, picoos_uchar * to, + picoos_uint8 * propset, + picoos_uint8 * stokenType, picoos_uint8 * stokenSubType, + picoos_uint8 * value, picoos_uchar * lowercase, + picoos_uchar * graphsubs1, picoos_uchar * graphsubs2, + picoos_uint8 * punct) { + ktabgraphs_subobj_t * g = (ktabgraphs_SubObj) this; + picoos_uint32 graphsOffset; + picoos_uint8 * pos; + + /* calculate offset of graph[graphIndex] */ + if (g->sizeOffset == 1) { + graphsOffset = g->offsetTable[graphIndex]; + } else { + graphsOffset = g->offsetTable[2 * graphIndex] + + (g->offsetTable[2 * graphIndex + 1] << 8); + } + pos = &(g->graphTable[graphsOffset]); + *propset = *pos; + + pos++; /* advance to FROM */ + ktab_getUtf8(&pos, from); /* get FROM and advance */ + if ((*propset) & KTAB_GRAPH_PROPSET_TO) { + ktab_getUtf8(&pos, to); /* get TO and advance */ + } else { + picoos_strcpy((picoos_char *)to, (picoos_char *)from); + } + if ((*propset) & KTAB_GRAPH_PROPSET_TOKENTYPE) { + (*stokenType) = *(pos++); /* get TOKENTYPE and advance */ + } else { + (*stokenType) = -1; + } + if ((*propset) & KTAB_GRAPH_PROPSET_TOKENSUBTYPE) { + (*stokenSubType) = *(pos++); /* get TOKENSUBTYPE and advance */ + } else { + (*stokenSubType) = -1; + } + if ((*propset) & KTAB_GRAPH_PROPSET_VALUE) { + (*value) = *(pos++); /* get VALUE and advance */ + } else { + (*value) = -1; + } + if ((*propset) & KTAB_GRAPH_PROPSET_LOWERCASE) { + ktab_getUtf8(&pos, lowercase); /* get LOWERCASE and advance */ + } else { + lowercase[0] = NULLC; + } + if ((*propset) & KTAB_GRAPH_PROPSET_GRAPHSUBS1) { + ktab_getUtf8(&pos, graphsubs1); /* get GRAPHSUBS1 and advance */ + } else { + graphsubs1[0] = NULLC; + } + if ((*propset) & KTAB_GRAPH_PROPSET_GRAPHSUBS2) { + ktab_getUtf8(&pos, graphsubs2); /* get GRAPHSUBS2 and advance */ + } else { + graphsubs2[0] = NULLC; + } + if ((*propset) & KTAB_GRAPH_PROPSET_PUNCT) { + (*punct) = *(pos++); /* get PUNCT and advance */ + } else { + (*punct) = -1; + } +} + +/* ************************************************************/ +/* Phones */ +/* ************************************************************/ + +/* overview binary file format for phones kb: + + phones-kb = specids propertytable + + specids = PRIMSTRESSID1 SECSTRESSID1 SYLLBOUNDID1 PAUSEID1 WORDBOUNDID1 + RESERVE1 RESERVE1 RESERVE1 + + propertytable = {PHONEPROP2}=256 + + PRIMSTRESSID1: one byte, ID of primary stress + SECSTRESSID1: one byte, ID of secondary stress + SYLLBOUNDID1: one byte, ID of syllable boundary + PAUSEID1: one byte, ID of pause + RESERVE1: reserved for future use + + PHONEPROP2: one byte, max. of 256 phones directly access this table + to check a property for a phone; binary properties + encoded (1 bit per prop) + least significant bit: vowel + next bit: diphth + next bit: glott + next bit: nonsyllvowel + next bit: syllcons + 3 bits spare + */ + +#define KTAB_START_SPECIDS 0 +#define KTAB_IND_PRIMSTRESS 0 +#define KTAB_IND_SECSTRESS 1 +#define KTAB_IND_SYLLBOUND 2 +#define KTAB_IND_PAUSE 3 +#define KTAB_IND_WORDBOUND 4 + +#define KTAB_START_PROPS 8 + + +typedef struct ktabphones_subobj *ktabphones_SubObj; + +typedef struct ktabphones_subobj { + picoos_uint8 *specids; + picoos_uint8 *props; +} ktabphones_subobj_t; + + +/* bitmasks to extract the property info from props */ +#define KTAB_PPROP_VOWEL '\x01' +#define KTAB_PPROP_DIPHTH '\x02' +#define KTAB_PPROP_GLOTT '\x04' +#define KTAB_PPROP_NONSYLLVOWEL '\x08' +#define KTAB_PPROP_SYLLCONS '\x10' + + +static pico_status_t ktabPhonesInitialize(register picoknow_KnowledgeBase this, + picoos_Common common) { + ktabphones_subobj_t * ktabphones; + + PICODBG_DEBUG(("start")); + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + ktabphones = (ktabphones_subobj_t *) this->subObj; + ktabphones->specids = &(this->base[KTAB_START_SPECIDS]); + ktabphones->props = &(this->base[KTAB_START_PROPS]); + return PICO_OK; +} + +static pico_status_t ktabPhonesSubObjDeallocate(register picoknow_KnowledgeBase this, + picoos_MemoryManager mm) { + if (NULL != this) { + picoos_deallocate(mm, (void *) &this->subObj); + } + return PICO_OK; +} + +pico_status_t picoktab_specializePhonesKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common) { + if (NULL == this) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + this->subDeallocate = ktabPhonesSubObjDeallocate; + this->subObj = picoos_allocate(common->mm, sizeof(ktabphones_subobj_t)); + if (NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, + NULL, NULL); + } + return ktabPhonesInitialize(this, common); +} + +picoktab_Phones picoktab_getPhones(picoknow_KnowledgeBase this) { + if (NULL == this) { + return NULL; + } else { + return (picoktab_Phones) this->subObj; + } +} + + +/* Phones methods */ + +picoos_uint8 picoktab_hasVowelProp(const picoktab_Phones this, + const picoos_uint8 ch) { + return (KTAB_PPROP_VOWEL & ((ktabphones_SubObj)this)->props[ch]); +} +picoos_uint8 picoktab_hasDiphthProp(const picoktab_Phones this, + const picoos_uint8 ch) { + return (KTAB_PPROP_DIPHTH & ((ktabphones_SubObj)this)->props[ch]); +} +picoos_uint8 picoktab_hasGlottProp(const picoktab_Phones this, + const picoos_uint8 ch) { + return (KTAB_PPROP_GLOTT & ((ktabphones_SubObj)this)->props[ch]); +} +picoos_uint8 picoktab_hasNonsyllvowelProp(const picoktab_Phones this, + const picoos_uint8 ch) { + return (KTAB_PPROP_NONSYLLVOWEL & ((ktabphones_SubObj)this)->props[ch]); +} +picoos_uint8 picoktab_hasSyllconsProp(const picoktab_Phones this, + const picoos_uint8 ch) { + return (KTAB_PPROP_SYLLCONS & ((ktabphones_SubObj)this)->props[ch]); +} + +picoos_bool picoktab_isSyllCarrier(const picoktab_Phones this, + const picoos_uint8 ch) { + picoos_uint8 props; + props = ((ktabphones_SubObj)this)->props[ch]; + return (((KTAB_PPROP_VOWEL & props) && + !(KTAB_PPROP_NONSYLLVOWEL & props)) + || (KTAB_PPROP_SYLLCONS & props)); +} + +picoos_bool picoktab_isPrimstress(const picoktab_Phones this, + const picoos_uint8 ch) { + return (ch == ((ktabphones_SubObj)this)->specids[KTAB_IND_PRIMSTRESS]); +} +picoos_bool picoktab_isSecstress(const picoktab_Phones this, + const picoos_uint8 ch) { + return (ch == ((ktabphones_SubObj)this)->specids[KTAB_IND_SECSTRESS]); +} +picoos_bool picoktab_isSyllbound(const picoktab_Phones this, + const picoos_uint8 ch) { + return (ch == ((ktabphones_SubObj)this)->specids[KTAB_IND_SYLLBOUND]); +} +picoos_bool picoktab_isWordbound(const picoktab_Phones this, + const picoos_uint8 ch) { + return (ch == ((ktabphones_SubObj)this)->specids[KTAB_IND_WORDBOUND]); +} +picoos_bool picoktab_isPause(const picoktab_Phones this, + const picoos_uint8 ch) { + return (ch == ((ktabphones_SubObj)this)->specids[KTAB_IND_PAUSE]); +} + +picoos_uint8 picoktab_getPrimstressID(const picoktab_Phones this) { + return ((ktabphones_SubObj)this)->specids[KTAB_IND_PRIMSTRESS]; +} +picoos_uint8 picoktab_getSecstressID(const picoktab_Phones this) { + return ((ktabphones_SubObj)this)->specids[KTAB_IND_SECSTRESS]; +} +picoos_uint8 picoktab_getSyllboundID(const picoktab_Phones this) { + return ((ktabphones_SubObj)this)->specids[KTAB_IND_SYLLBOUND]; +} +picoos_uint8 picoktab_getWordboundID(const picoktab_Phones this) { + return ((ktabphones_SubObj)this)->specids[KTAB_IND_WORDBOUND]; +} +picoos_uint8 picoktab_getPauseID(const picoktab_Phones this) { + return ((ktabphones_SubObj)this)->specids[KTAB_IND_PAUSE]; +} + +/* ************************************************************/ +/* Pos */ +/* ************************************************************/ + +/* overview binary file format for pos kb: + + pos-kb = header posids + header = {COUNT2 OFFS2}=8 + posids = {POSID1 {PARTID1}0:8}1: + + where POSID1 is the value of the (combined) part-of-speech symbol, + and {PARTID1} are the symbol values of its components (empty if it + is not a combined symbol). The {PARTID1} list is sorted. + Part-of-speech symbols with equal number of components are grouped + together. + + The header contains information about these groups: + + COUNT2 specifies the number of elements in the group, and OFFS2 + specifies the offset (relative to the beginning of the kb) where + the group data starts, i.e.: + + 25 32 -> 25 not-combined elements, starting at offset 32 + 44 57 -> 44 elements composed of 2 symbols, starting at offset 57 + 23 189 -> 23 elements composed of 3 symbols, starting at offset 189 + ... + + Currently, each symbol may be composed of up to 8 other symbols. + Therefore, the header has 8 entries, too. The header starts with + the unique POS list, and then in increasing order, 2 symbols, 3 + symbols,... + +Zur Anschauung die ge-printf-te Version: + + 25 32 + 44 57 + 23 189 + 12 281 + 4 341 + 1 365 + 0 0 + 0 0 + 33 | + 34 | + 35 | + 60 | + etc. + 36 | 35 60 + 50 | 35 95 + 51 | 35 97 + 58 | 35 120 + 59 | 35 131 + 61 | 60 75 + 63 | 60 95 + 64 | 60 97 + etc. + 42 | 35 60 117 + 44 | 35 60 131 + 45 | 35 73 97 + 48 | 35 84 97 + 54 | 35 97 131 + 56 | 35 113 120 + 57 | 35 117 120 + 62 | 60 84 122 + etc. + */ + +typedef struct ktabpos_subobj *ktabpos_SubObj; + +typedef struct ktabpos_subobj { + picoos_uint16 nrcomb[PICOKTAB_MAXNRPOS_IN_COMB]; + picoos_uint8 *nrcombstart[PICOKTAB_MAXNRPOS_IN_COMB]; +} ktabpos_subobj_t; + + +static pico_status_t ktabPosInitialize(register picoknow_KnowledgeBase this, + picoos_Common common) { + ktabpos_subobj_t *ktabpos; + picoos_uint16 osprev; + picoos_uint16 os, pos; + picoos_uint8 i; + + PICODBG_DEBUG(("start")); + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + ktabpos = (ktabpos_subobj_t *)this->subObj; + + os = 0; + for (i = 0, pos = 0; i < PICOKTAB_MAXNRPOS_IN_COMB; i++, pos += 4) { + ktabpos->nrcomb[i] = ((picoos_uint16)(this->base[pos+1])) << 8 | + this->base[pos]; + if (ktabpos->nrcomb[i] > 0) { + osprev = os; + os = ((picoos_uint16)(this->base[pos+3])) << 8 | this->base[pos+2]; + ktabpos->nrcombstart[i] = &(this->base[os]); + PICODBG_TRACE(("i %d, pos %d, nr %d, osprev %d, os %d", i, pos, + ktabpos->nrcomb[i], osprev, os)); + if (osprev >= os) { + /* cannot be, in a valid kb */ + return picoos_emRaiseException(common->em, + PICO_EXC_FILE_CORRUPT, + NULL, NULL); + } + } else { + if (i == 0) { + /* cannot be, in a valid kb */ + return picoos_emRaiseException(common->em, + PICO_EXC_FILE_CORRUPT, + NULL, NULL); + } + ktabpos->nrcombstart[i] = NULL; + } + } + return PICO_OK; +} + +static pico_status_t ktabPosSubObjDeallocate(register picoknow_KnowledgeBase this, + picoos_MemoryManager mm) { + if (NULL != this) { + picoos_deallocate(mm, (void *) &this->subObj); + } + return PICO_OK; +} + +pico_status_t picoktab_specializePosKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common) { + if (NULL == this) { + return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + this->subDeallocate = ktabPosSubObjDeallocate; + this->subObj = picoos_allocate(common->mm, sizeof(ktabpos_subobj_t)); + if (NULL == this->subObj) { + return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, + NULL, NULL); + } + return ktabPosInitialize(this, common); +} + +picoktab_Pos picoktab_getPos(picoknow_KnowledgeBase this) { + if (NULL == this) { + return NULL; + } else { + return (picoktab_Pos) this->subObj; + } +} + + +/* Pos methods */ + +static picoos_int16 ktab_isEqualPosGroup(const picoos_uint8 *grp1, + const picoos_uint8 *grp2, + picoos_uint8 len) +{ + /* if both, grp1 and grp2 would be sorted in ascending order + we could implement a function picoktab_comparePosGroup in + a similar manner as strcmp */ + + picoos_uint16 i, j, equal; + + equal = 1; + + i = 0; + while (equal && (i < len)) { + /* search grp1[i] in grp2 */ + j = 0; + while ((j < len) && (grp1[i] != grp2[j])) { + j++; + } + equal = (j < len); + i++; + } + + return equal; +} + + +picoos_bool picoktab_isUniquePos(const picoktab_Pos this, + const picoos_uint8 pos) { + ktabpos_subobj_t *ktabpos; + picoos_uint16 i; + + /* speed-up possible with e.g. binary search */ + + ktabpos = (ktabpos_subobj_t *)this; + PICODBG_TRACE(("pos %d, nrcombinations %d", pos, ktabpos->nrcomb[0])); + i = 0; + while ((i < ktabpos->nrcomb[0]) && (pos > ktabpos->nrcombstart[0][i])) { + PICODBG_TRACE(("compare with pos %d at position %d", + ktabpos->nrcombstart[0][i], pos, i)); + i++; + } + return ((i < ktabpos->nrcomb[0]) && (pos == ktabpos->nrcombstart[0][i])); +} + + +picoos_bool picoktab_isPartOfPosGroup(const picoktab_Pos this, + const picoos_uint8 pos, + const picoos_uint8 posgroup) +{ + ktabpos_subobj_t *ktabpos; + picoos_uint8 *grp; + picoos_uint16 i, j, n, s, grplen; + picoos_uint8 *e; + picoos_uint8 found; + + ktabpos = (ktabpos_subobj_t *) this; + + grp = NULL; + found = FALSE; + grplen = 0; + + /* currently, a linear search is required to find 'posgroup'; the + knowledge base should be extended to allow for a faster search */ + + /* treat case i==0, grplen==0, ie. pos == posgroup */ + if (pos == posgroup) { + found = TRUE; + } + + i = 1; + while ((grp == NULL) && (i < PICOKTAB_MAXNRPOS_IN_COMB)) { + n = ktabpos->nrcomb[i]; /* number of entries */ + e = ktabpos->nrcombstart[i]; /* ptr to first entry */ + s = i + 2; /* size of an entry in bytes */ + /* was with while starting at 0: + s = i > 0 ? i + 2 : 1; + */ + j = 0; + while ((grp == NULL) && (j < n)) { + if (posgroup == e[0]) { + grp = e + 1; + grplen = s - 1; + } + e += s; + j++; + } + i++; + } + + /* test if 'pos' is contained in the components of 'posgroup' */ + if (grp != NULL) { + for (i = 0; !found && (i < grplen); i++) { + if (pos == grp[i]) { + found = TRUE; + } + } + + /* just a way to test picoktab_getPosGroup */ + /* + PICODBG_ASSERT(picoktab_getPosGroup(this, grp, grplen) == posgroup); + */ + } + + return found; +} + + +picoos_uint8 picoktab_getPosGroup(const picoktab_Pos this, + const picoos_uint8 *poslist, + const picoos_uint8 poslistlen) +{ + picoos_uint8 poscomb; + ktabpos_subobj_t *ktabpos; + picoos_uint16 i, j, n, s; + picoos_uint8 *e; + + ktabpos = (ktabpos_subobj_t *) this; + poscomb = 0; + + if ((poslistlen > 0) && (poslistlen <= PICOKTAB_MAXNRPOS_IN_COMB)) { + i = poslistlen - 1; + if (i > 0) { + n = ktabpos->nrcomb[i]; /* number of entries */ + e = ktabpos->nrcombstart[i]; /* ptr to first entry */ + s = i + 2; /* size of an entry in bytes */ + j = 0; + while (!poscomb && (j < n)) { + if (ktab_isEqualPosGroup(poslist, e + 1, poslistlen)) { + poscomb = *e; + } + e += s; + j++; + } + if (!poscomb) { + /* combination not found; shouldn't occur if lingware OK! */ + /* contingency solution: take first */ + PICODBG_WARN(("dynamically created POS combination not found in table; taking first (%i)",poslist[0])); + poscomb = poslist[0]; + } + } else { /* not a composed POS */ + poscomb = poslist[0]; + } + } + + return poscomb; +} + +#ifdef __cplusplus +} +#endif + + +/* end */ diff --git a/pico/lib/picoktab.h b/pico/lib/picoktab.h new file mode 100644 index 0000000..71ba2ab --- /dev/null +++ b/pico/lib/picoktab.h @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picoktab.h + * + * symbol tables needed at runtime + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ +/** + * @addtogroup picoktab + + * Symbol tables needed at runtime \n + * +*/ + +#ifndef PICOKTAB_H_ +#define PICOKTAB_H_ + +#include "picoos.h" +#include "picoknow.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* ************************************************************/ +/* fixed IDs type and functions */ +/* ************************************************************/ + +/** object : FixedIds + * shortcut : ids + */ +typedef struct picoktab_fixed_ids * picoktab_FixedIds; + +typedef struct picoktab_fixed_ids { + picoos_uint8 phonStartId; + picoos_uint8 phonTermId; +} picoktab_fixed_ids_t; + +/* to be used by picorsrc only */ +pico_status_t picoktab_specializeIdsKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common); + +picoktab_FixedIds picoktab_getFixedIds(picoknow_KnowledgeBase this); + + +/* ************************************************************/ +/* Graphs type and functions */ +/* ************************************************************/ + +typedef struct picoktab_graphs *picoktab_Graphs; + +/* to be used by picorsrc only */ +pico_status_t picoktab_specializeGraphsKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common); + +/* return kb graphs for usage in PU */ +picoktab_Graphs picoktab_getGraphs(picoknow_KnowledgeBase this); + +/* graph access routine: if the desired graph 'utf8graph' exists in + the graph table a graph offset > 0 is returned, which then can be + used to access the properties */ +picoos_uint32 picoktab_graphOffset(const picoktab_Graphs this, + picoos_uchar * utf8graph); + + +/* check if UTF8 char 'graph' has property vowellike, return non-zero + if 'ch' has the property, 0 otherwise */ +picoos_uint8 picoktab_hasVowellikeProp(const picoktab_Graphs this, + const picoos_uint8 *graph, + const picoos_uint8 graphlenmax); + +/* graph properties access routines: if graph with offset 'graphsOffset' has the + desired property, returns TRUE if 'ch' has the property, FALSE otherwise */ +picoos_bool picoktab_getIntPropTokenType(const picoktab_Graphs this, + picoos_uint32 graphsOffset, + picoos_uint8 *stokenType); +picoos_bool picoktab_getIntPropTokenSubType(const picoktab_Graphs this, + picoos_uint32 graphsOffset, + picoos_int8 *stokenSubType); +picoos_bool picoktab_getIntPropValue(const picoktab_Graphs this, + picoos_uint32 graphsOffset, + picoos_uint32 *value); +picoos_bool picoktab_getStrPropLowercase(const picoktab_Graphs this, + picoos_uint32 graphsOffset, + picoos_uchar *lowercase); +picoos_bool picoktab_getStrPropGraphsubs1(const picoktab_Graphs this, + picoos_uint32 graphsOffset, + picoos_uchar *graphsubs1); +picoos_bool picoktab_getStrPropGraphsubs2(const picoktab_Graphs this, + picoos_uint32 graphsOffset, + picoos_uchar *graphsubs2); +picoos_bool picoktab_getIntPropPunct(const picoktab_Graphs this, + picoos_uint32 graphsOffset, + picoos_uint8 *info1, + picoos_uint8 *info2); + +picoos_uint16 picoktab_graphsGetNumEntries(const picoktab_Graphs this); +void picoktab_graphsGetGraphInfo(const picoktab_Graphs this, + picoos_uint16 graphIndex, picoos_uchar * from, picoos_uchar * to, + picoos_uint8 * propset, + picoos_uint8 * stokenType, picoos_uint8 * stokenSubType, + picoos_uint8 * value, picoos_uchar * lowercase, + picoos_uchar * graphsubs1, picoos_uchar * graphsubs2, + picoos_uint8 * punct); + + +/* ************************************************************/ +/* Phones type and functions */ +/* ************************************************************/ + +/* to be used by picorsrc only */ +pico_status_t picoktab_specializePhonesKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common); + +typedef struct picoktab_phones *picoktab_Phones; + +/* return kb Phones for usage in PU */ +picoktab_Phones picoktab_getPhones(picoknow_KnowledgeBase this); + +/* check if 'ch' has a property, return non-zero if 'ch' has the + property, 0 otherwise */ +picoos_uint8 picoktab_hasVowelProp(const picoktab_Phones this, + const picoos_uint8 ch); +picoos_uint8 picoktab_hasDiphthProp(const picoktab_Phones this, + const picoos_uint8 ch); +picoos_uint8 picoktab_hasGlottProp(const picoktab_Phones this, + const picoos_uint8 ch); +picoos_uint8 picoktab_hasNonsyllvowelProp(const picoktab_Phones this, + const picoos_uint8 ch); +picoos_uint8 picoktab_hasSyllconsProp(const picoktab_Phones this, + const picoos_uint8 ch); + +/* to speed up processing for often used combinations of properties + the following functions are provided, which check if the property + combination is true for 'ch' */ +picoos_bool picoktab_isSyllCarrier(const picoktab_Phones this, + const picoos_uint8 ch); + +/* some properties can be assigned to a single sym only, check if 'ch' + is a special sym, return TRUE if it is the special sym, FALSE + otherwise */ +picoos_bool picoktab_isPrimstress(const picoktab_Phones this, + const picoos_uint8 ch); +picoos_bool picoktab_isSecstress(const picoktab_Phones this, + const picoos_uint8 ch); +picoos_bool picoktab_isSyllbound(const picoktab_Phones this, + const picoos_uint8 ch); +picoos_bool picoktab_isWordbound(const picoktab_Phones this, + const picoos_uint8 ch); +picoos_bool picoktab_isPause(const picoktab_Phones this, + const picoos_uint8 ch); + +/* get specific sym values */ +picoos_uint8 picoktab_getPrimstressID(const picoktab_Phones this); +picoos_uint8 picoktab_getSecstressID(const picoktab_Phones this); +picoos_uint8 picoktab_getSyllboundID(const picoktab_Phones this); +picoos_uint8 picoktab_getWordboundID(const picoktab_Phones this); +picoos_uint8 picoktab_getPauseID(const picoktab_Phones this); + +/* ************************************************************/ +/* Pos type and functions */ +/* ************************************************************/ + +/* to be used by picorsrc only */ +pico_status_t picoktab_specializePosKnowledgeBase(picoknow_KnowledgeBase this, + picoos_Common common); + +typedef struct picoktab_pos *picoktab_Pos; + +#define PICOKTAB_MAXNRPOS_IN_COMB 8 + +/* return kb Pos for usage in PU */ +picoktab_Pos picoktab_getPos(picoknow_KnowledgeBase this); + +/* returns TRUE if 'pos' is the ID of a unique (ie. non-combined) POS, + returns FALSE otherwise */ +picoos_bool picoktab_isUniquePos(const picoktab_Pos this, + const picoos_uint8 pos); + +/* returns TRUE if the non-combined 'pos' is one of the POSes in the + combined POS group 'posgroup, returns FALSE otherwise. Note: if + 'posgroup' is itself non-combined, this function returns TRUE if it + matches with 'pos', and FALSE otherwise */ +picoos_bool picoktab_isPartOfPosGroup(const picoktab_Pos this, + const picoos_uint8 pos, + const picoos_uint8 posgroup); + +/* return the combined POS group ID that is a representative ID for + all the 'poslistlen' POSes (which can be combined themselves) in + poslist. Returns '0' in case of error. */ +picoos_uint8 picoktab_getPosGroup(const picoktab_Pos this, + const picoos_uint8 *poslist, + const picoos_uint8 poslistlen); + +#ifdef __cplusplus +} +#endif + + +#endif /*PICOKTAB_H_*/ diff --git a/pico/lib/picoos.c b/pico/lib/picoos.c new file mode 100644 index 0000000..0ab9bf8 --- /dev/null +++ b/pico/lib/picoos.c @@ -0,0 +1,2309 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picoos.c + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include +#include "picodefs.h" +#include "picopal.h" +#include "picoos.h" +#include "picodbg.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +#define picoos_SVOXFileHeader (picoos_char *)" (C) SVOX AG " + +/* ********************************************** + * default error and warning messages + * **********************************************/ + + +#define PICOOS_MSG_EXC_NUMBER_FORMAT (picoos_char *) "wrong number format" +#define PICOOS_MSG_EXC_MAX_NUM_EXCEED (picoos_char *) "number exceeded" +#define PICOOS_MSG_EXC_NAME_CONFLICT (picoos_char *) "name conflict" +#define PICOOS_MSG_EXC_NAME_UNDEFINED (picoos_char *) "name undefined" +#define PICOOS_MSG_EXC_NAME_ILLEGAL (picoos_char *) "illegal name" + +/* buffer interaction */ +#define PICOOS_MSG_EXC_BUF_OVERFLOW (picoos_char *) "buffer overflow" +#define PICOOS_MSG_EXC_BUF_UNDERFLOW (picoos_char *) "buffer underflow" +#define PICOOS_MSG_EXC_BUF_IGNORE (picoos_char *) "buffer error" + +/* memory allocation */ +#define PICOOS_MSG_EXC_OUT_OF_MEM (picoos_char *) "out of memory" + +/* files */ +#define PICOOS_MSG_EXC_CANT_OPEN_FILE (picoos_char *) "cannot open file" +#define PICOOS_MSG_EXC_UNEXPECTED_FILE_TYPE (picoos_char *) "unexpected file type" +#define PICOOS_MSG_EXC_FILE_CORRUPT (picoos_char *) "corrupt file" +#define PICOOS_MSG_EXC_FILE_NOT_FOUND (picoos_char *) "file not found" + +/* resources */ +#define PICOOS_MSG_EXC_RESOURCE_BUSY (picoos_char *) "resource is busy" +#define PICOOS_MSG_EXC_RESOURCE_MISSING (picoos_char *) "cannot find resource" + +/* knowledge bases */ +#define PICOOS_MSG_EXC_KB_MISSING (picoos_char *) "knowledge base missing" + +/* runtime exceptions (programming problems, usually a bug. E.g. trying to access null pointer) */ +#define PICOOS_MSG_ERR_NULLPTR_ACCESS (picoos_char *) "access violation" +#define PICOOS_MSG_ERR_INVALID_HANDLE (picoos_char *) "invalid handle value" +#define PICOOS_MSG_ERR_INVALID_ARGUMENT (picoos_char *) "invalid argument supplied" +#define PICOOS_MSG_ERR_INDEX_OUT_OF_RANGE (picoos_char *) "index out of range" + + +/* errors ("external" errors, e.g. hardware failure. Usually cannot be dealt with from inside pico.) */ +#define PICOOS_MSG_ERR_OTHER (picoos_char *) "other error" + +#define PICOOS_MSG_ERR_PU (picoos_char *) "error in processing unit" + +/* WARNINGS */ + +/* general */ +#define PICOOS_MSG_WARN_INCOMPLETE (picoos_char *) "incomplete output" +#define PICOOS_MSG_WARN_FALLBACK (picoos_char *) "using fall-back" +#define PICOOS_MSG_WARN_OTHER (picoos_char *) "other warning" + +/* resources */ +#define PICOOS_MSG_WARN_KB_OVERWRITE (picoos_char *) "overwriting knowledge base" +#define PICOOS_MSG_WARN_RESOURCE_DOUBLE_LOAD (picoos_char *) "resource already loaded" + +/* decision trees */ +#define PICOOS_MSG_WARN_INVECTOR (picoos_char *) "input vector not constructed" +#define PICOOS_MSG_WARN_CLASSIFICATION (picoos_char *) "output not classified" +#define PICOOS_MSG_WARN_OUTVECTOR (picoos_char *) "output vector not decomposed" + +/* processing units */ +#define PICOOS_MSG_WARN_PU_IRREG_ITEM (picoos_char *) "irregular item in processing unit" +#define PICOOS_MSG_WARN_PU_DISCARD_BUF (picoos_char *) "discarding processing unit buffer" + + +/* ********************************************** + * wrappers for picopal functions + * **********************************************/ + +picoos_int32 picoos_atoi(const picoos_char *s) +{ + return (picoos_int32)picopal_atoi((const picoos_char *)s); +} + + +picoos_int8 picoos_strcmp(const picoos_char *a, const picoos_char *b) +{ + picopal_int32 res = picopal_strcmp((const picopal_char *)a, + (const picopal_char *)b); + return (picoos_int8) ((res < 0) ? -1 : (res > 0) ? 1 : 0); +} +picoos_int8 picoos_strncmp(const picoos_char *a, const picoos_char *b, picoos_objsize_t siz) +{ + picopal_int32 res = picopal_strncmp((const picopal_char *)a, + (const picopal_char *)b, siz); + return (picoos_int8) ((res < 0) ? -1 : (res > 0) ? 1 : 0); +} + +picoos_uint32 picoos_strlen(const picoos_char *s) +{ + return (picoos_uint32)picopal_strlen((const picopal_char *)s); +} + +picoos_char *picoos_strchr(const picoos_char *s, picoos_char c) +{ + return (picoos_char *)picopal_strchr((const picopal_char *)s, + (picopal_char)c); +} + +picoos_char *picoos_strstr(const picoos_char *s, const picoos_char * substr) +{ + return (picoos_char *)picopal_strstr((const picopal_char *)s, + (const picopal_char *)substr); +} + +picoos_int16 picoos_slprintf(picoos_char * b, picoos_uint32 bsize, const picoos_char *f, ...) +{ + picopal_int16 i; + va_list args; + + va_start(args, (char *)f); + i = (picoos_int16)picopal_vslprintf((picoos_char *) b, bsize, (const picoos_char *)f, args); + va_end(args); + return i; +} + +picoos_char *picoos_strcpy(picoos_char *d, const picoos_char *s) +{ + return (picoos_char *)picopal_strcpy((picopal_char *)d, + (const picopal_char *)s); +} + +picoos_char *picoos_strcat(picoos_char *d, const picoos_char *s) +{ + return (picoos_char *)picopal_strcat((picopal_char *)d, + (const picopal_char *)s); +} + +picoos_objsize_t picoos_strlcpy(picoos_char *dst, const picoos_char *src, picoos_objsize_t siz) +{ + return (picoos_objsize_t) picopal_strlcpy((picopal_char *) dst, (const picopal_char *) src, (picopal_objsize_t) siz); +} + +/* copies 'length' bytes from 'src' to 'dest'. (regions may be overlapping) no error checks! */ +void * picoos_mem_copy(const void * src, void * dst, picoos_objsize_t length) +{ + return picopal_mem_copy(src,dst,(picopal_objsize_t) length); +} + +/* sets 'length' bytes starting at dest[0] to 'byte_val' */ +void * picoos_mem_set(void * dest, picoos_uint8 byte_val, picoos_objsize_t length) { + return picopal_mem_set(dest,(picopal_uint8)byte_val, (picopal_objsize_t)length); +} + + +picoos_double picoos_cos (const picoos_double cos_arg) +{ + return (picoos_double) picopal_cos ((picopal_double) cos_arg); +} + + +picoos_double picoos_sin (const picoos_double sin_arg) +{ + return (picoos_double) picopal_sin((picopal_double) sin_arg); +} +picoos_double picoos_fabs (const picoos_double fabs_arg) +{ + return (picoos_double) picopal_fabs((picopal_double) fabs_arg); +} + +picoos_double picoos_quick_exp(const picoos_double y) { + return (picoos_double) picopal_quick_exp ((picopal_double)y); +} + + +/* *****************************************************************/ +/* "Common" */ +/* *****************************************************************/ +/* picoos_common is a collection of basic functionalities that must be globally + * accessible from every "big" function. It includes pointers to the MemoryManasger, + * ExceptionManager and a system-wide list of open files. */ + +picoos_Common picoos_newCommon(picoos_MemoryManager mm) +{ + picoos_Common this = (picoos_Common) picoos_allocate(mm,sizeof(*this)); + if (NULL != this) { + /* initialize */ + this->em = NULL; + this->mm = NULL; + this->fileList = NULL; + } + return this; +} + +void picoos_disposeCommon(picoos_MemoryManager mm, picoos_Common * this) +{ + if (NULL != (*this)) { + /* terminate */ + picoos_deallocate(mm,(void *)this); + } +} + + +/* *****************************************************************/ +/* Memory Management */ +/* *****************************************************************/ + +typedef struct mem_block_hdr * MemBlockHdr; +typedef struct mem_block_hdr +{ + MemBlockHdr next; + byte_ptr_t data; + picoos_objsize_t size; +} mem_block_hdr_t; + +typedef struct mem_cell_hdr * MemCellHdr; +typedef struct mem_cell_hdr +{ + /* size may be <0 if used */ + picoos_ptrdiff_t size; + MemCellHdr leftCell; + MemCellHdr prevFree, nextFree; +} mem_cell_hdr_t; + +typedef struct memory_manager +{ + MemBlockHdr firstBlock, lastBlock; /* memory blockList */ + MemCellHdr freeCells, lastFree; /* free memory cells (first/last sentinel */ + /* "constants" */ + picoos_objsize_t fullCellHdrSize; /* aligned size of full cell header, including free-links */ + picoos_objsize_t usedCellHdrSize; /* aligned size of header part without free-links */ + picoos_objsize_t minContSize; /* minimum requestable application content size for allocation; + must hold free-list info; = fullCellHdrSize-usedCellHdrSize */ + picoos_objsize_t minCellSize; /* minimum remaining cell size when a free cell is split */ + picoos_bool protMem; /* true if memory protection is enabled */ + picoos_ptrdiff_t usedSize; + picoos_ptrdiff_t prevUsedSize; + picoos_ptrdiff_t maxUsedSize; +} memory_manager_t; + +/** allocates 'alloc_size' bytes at start of raw memory block ('raw_mem',raw_mem_size) + * and returns pointer to allocated region. Returns remaining (correctly aligned) raw memory block + * in ('rest_mem','rest_mem_size'). + * The allocated memory is not subject to memory management, so that it can never be freed again! + * + */ +void * picoos_raw_malloc(byte_ptr_t raw_mem, + picoos_objsize_t raw_mem_size, picoos_objsize_t alloc_size, + byte_ptr_t * rest_mem, picoos_objsize_t * rest_mem_size) +{ + picoos_ptrdiff_t rest; + if (raw_mem == NULL) { + return NULL; + } else { + if (alloc_size < 1) { + alloc_size = 1; + } + alloc_size = ((alloc_size + PICOOS_ALIGN_SIZE - 1) / PICOOS_ALIGN_SIZE) + * PICOOS_ALIGN_SIZE; + + rest = raw_mem_size - alloc_size; + if (rest < 0) { + return NULL; + } else { + *rest_mem_size = rest; + *rest_mem = raw_mem + alloc_size; + return (void *) raw_mem; + } + } +} + +/** initializes the last block of mm */ +static int os_init_mem_block(picoos_MemoryManager this) +{ + int isFirstBlock; + void * newBlockAddr; + picoos_objsize_t size; + MemCellHdr cbeg, cmid, cend; + + isFirstBlock = (this->freeCells == NULL); + newBlockAddr = (void *) this->lastBlock->data; + size = this->lastBlock->size; + cbeg = (MemCellHdr) newBlockAddr; + cmid = (MemCellHdr)((picoos_objsize_t)newBlockAddr + this->fullCellHdrSize); + cend = (MemCellHdr)((picoos_objsize_t)newBlockAddr + size + - this->fullCellHdrSize); + cbeg->size = 0; + + cbeg->leftCell = NULL; + cmid->size = size - 2 * this->fullCellHdrSize; + cmid->leftCell = cbeg; + cend->size = 0; + cend->leftCell = cmid; + if (isFirstBlock) { + cbeg->nextFree = cmid; + cbeg->prevFree = NULL; + cmid->nextFree = cend; + cmid->prevFree = cbeg; + cend->nextFree = NULL; + cend->prevFree = cmid; + this->freeCells = cbeg; + this->lastFree = cend; + } else { + /* add cmid to free cell list */ + cbeg->nextFree = NULL; + cbeg->prevFree = NULL; + cmid->nextFree = this->freeCells->nextFree; + cmid->prevFree = this->freeCells; + cmid->nextFree->prevFree = cmid; + cmid->prevFree->nextFree = cmid; + cend->nextFree = NULL; + cbeg->prevFree = NULL; + } + return PICO_OK; +} + + +picoos_MemoryManager picoos_newMemoryManager( + void *raw_memory, + picoos_objsize_t size, + picoos_bool enableMemProt) +{ + byte_ptr_t rest_mem; + picoos_objsize_t rest_mem_size; + picoos_MemoryManager this; + picoos_objsize_t size2; + mem_cell_hdr_t test_cell; + + this = picoos_raw_malloc(raw_memory, size, sizeof(memory_manager_t), + &rest_mem, &rest_mem_size); + if (this == NULL) { + return NULL; + } + + /* test if memory protection functionality is available on the current + platform (if not, picopal_mpr_alloc() always returns NULL) */ + if (enableMemProt) { + void *addr = picopal_mpr_alloc(100); + if (addr == NULL) { + enableMemProt = FALSE; + } else { + picopal_mpr_free(&addr); + } + } + + this->firstBlock = NULL; + this->lastBlock = NULL; + this->freeCells = NULL; + this->lastFree = NULL; + + this->protMem = enableMemProt; + this->usedSize = 0; + this->prevUsedSize = 0; + this->maxUsedSize = 0; + + /* get aligned full header size */ + this->fullCellHdrSize = ((sizeof(mem_cell_hdr_t) + PICOOS_ALIGN_SIZE - 1) + / PICOOS_ALIGN_SIZE) * PICOOS_ALIGN_SIZE; + /* get aligned size of header without free-list fields; the result may be compiler-dependent; + the size is therefore computed by inspecting the end addresses of the fields 'size' and 'leftCell'; + the higher of the ending addresses is used to get the (aligned) starting address + of the application contents */ + this->usedCellHdrSize = (picoos_objsize_t) &test_cell.size + - (picoos_objsize_t) &test_cell + sizeof(picoos_objsize_t); + size2 = (picoos_objsize_t) &test_cell.leftCell - (picoos_objsize_t) + &test_cell + sizeof(MemCellHdr); + if (size2 > this->usedCellHdrSize) { + this->usedCellHdrSize = size2; + } + /* get minimum application-usable size; must be large enough to hold remainder of + cell header (free-list links) when in free-list */ + this->minContSize = this->fullCellHdrSize - this->usedCellHdrSize; + /* get minimum required size of a cell remaining after a cell split */ + this->minCellSize = this->fullCellHdrSize + PICOOS_ALIGN_SIZE; + + /* install remainder of raw memory block as first block */ + raw_memory = rest_mem; + size = rest_mem_size; + this->firstBlock = this->lastBlock = picoos_raw_malloc(raw_memory, size, + sizeof(mem_block_hdr_t), &rest_mem, &rest_mem_size); + if (this->lastBlock == NULL) { + return NULL; + } + this->lastBlock->next = NULL; + this->lastBlock->data = rest_mem; + this->lastBlock->size = rest_mem_size; + + os_init_mem_block(this); + + return this; +} + +void picoos_disposeMemoryManager(picoos_MemoryManager * mm) +{ + *mm = NULL; +} + + +/* the following memory manager routines are for testing and + debugging purposes */ + + +void *picoos_allocProtMem(picoos_MemoryManager mm, picoos_objsize_t byteSize) +{ + if (mm->protMem) { + return picopal_mpr_alloc(byteSize); + } else { + return picoos_allocate(mm, byteSize); + } +} + + +void picoos_deallocProtMem(picoos_MemoryManager mm, void **addr) +{ + if (mm->protMem) { + picopal_mpr_free(addr); + } else { + picoos_deallocate(mm, addr); + } +} + + +void picoos_protectMem( + picoos_MemoryManager mm, + void *addr, + picoos_objsize_t len, + picoos_bool enable) +{ + if (mm->protMem) { + int prot = PICOPAL_PROT_READ; + if (!enable) { + prot |= PICOPAL_PROT_WRITE; + } + picopal_mpr_protect(addr, len, prot); + } else { + /* memory protection disabled; nothing to do */ + } +} + +#define PICOPAL_PROT_NONE 0 /* the memory cannot be accessed at all */ +#define PICOPAL_PROT_READ 1 /* the memory can be read */ +#define PICOPAL_PROT_WRITE 2 /* the memory can be written to */ + +void picoos_getMemUsage( + picoos_MemoryManager this, + picoos_bool resetIncremental, + picoos_int32 *usedBytes, + picoos_int32 *incrUsedBytes, + picoos_int32 *maxUsedBytes) +{ + *usedBytes = (picoos_int32) this->usedSize; + *incrUsedBytes = (picoos_int32) (this->usedSize - this->prevUsedSize); + *maxUsedBytes = (picoos_int32) this->maxUsedSize; + if (resetIncremental) { + this->prevUsedSize = this->usedSize; + } +} + + +void picoos_showMemUsage(picoos_MemoryManager this, picoos_bool incremental, + picoos_bool resetIncremental) +{ + picoos_int32 usedBytes, incrUsedBytes, maxUsedBytes; + + picoos_getMemUsage(this, resetIncremental, &usedBytes, &incrUsedBytes, + &maxUsedBytes); + if (incremental) { + PICODBG_DEBUG(("additional memory used: %d", incrUsedBytes)); + } else { + PICODBG_DEBUG(("memory used: %d, maximally used: %d", usedBytes, maxUsedBytes)); + } +} + + +void * picoos_allocate(picoos_MemoryManager this, + picoos_objsize_t byteSize) +{ + + picoos_objsize_t cellSize; + MemCellHdr c, c2, c2r; + void * adr; + + if (byteSize < this->minContSize) { + byteSize = this->minContSize; + } + byteSize = ((byteSize + PICOOS_ALIGN_SIZE - 1) / PICOOS_ALIGN_SIZE) + * PICOOS_ALIGN_SIZE; + + cellSize = byteSize + this->usedCellHdrSize; + /*PICODBG_TRACE(("allocating %d", cellSize));*/ + c = this->freeCells->nextFree; + while ( + (c != NULL) && + (c->size != (picoos_ptrdiff_t) cellSize) && + (c->size < (picoos_ptrdiff_t)(cellSize+ this->minCellSize))) { + c = c->nextFree; + } + if (c == NULL) { + return NULL; + } + if (c->size == (picoos_ptrdiff_t) cellSize) { + c->prevFree->nextFree = c->nextFree; + c->nextFree->prevFree = c->prevFree; + } else { + c2 = (MemCellHdr)((picoos_objsize_t)c + cellSize); + c2->size = c->size - cellSize; + c->size = cellSize; + c2->leftCell = c; + c2r = (MemCellHdr)((picoos_objsize_t)c2 + c2->size); + c2r->leftCell = c2; + c2->nextFree = c->nextFree; + c2->nextFree->prevFree = c2; + c2->prevFree = c->prevFree; + c2->prevFree->nextFree = c2; + } + + /* statistics */ + this->usedSize += cellSize; + if (this->usedSize > this->maxUsedSize) { + this->maxUsedSize = this->usedSize; + } + + c->size = -(c->size); + adr = (void *)((picoos_objsize_t)c + this->usedCellHdrSize); + return adr; +} + +void picoos_deallocate(picoos_MemoryManager this, void * * adr) +{ + MemCellHdr c; + MemCellHdr cr; + MemCellHdr cl; + MemCellHdr crr; + + + if ((*adr) != NULL) { + c = (MemCellHdr)((picoos_objsize_t)(*adr) - this->usedCellHdrSize); + c->size = -(c->size); + + /*PICODBG_TRACE(("deallocating %d", c->size));*/ + /* statistics */ + this->usedSize -= c->size; + + cr = (MemCellHdr)((picoos_objsize_t)c + c->size); + cl = c->leftCell; + if (cl->size > 0) { + if (cr->size > 0) { + crr = (MemCellHdr)((picoos_objsize_t)cr + cr->size); + crr->leftCell = cl; + cl->size = ((cl->size + c->size) + cr->size); + cr->nextFree->prevFree = cr->prevFree; + cr->prevFree->nextFree = cr->nextFree; + } else { + cl->size = (cl->size + c->size); + cr->leftCell = cl; + } + } else { + if ((cr->size > 0)) { + crr = (MemCellHdr)((picoos_objsize_t)cr + cr->size); + crr->leftCell = c; + c->size = (c->size + cr->size); + c->nextFree = cr->nextFree; + c->prevFree = cr->prevFree; + c->nextFree->prevFree = c; + c->prevFree->nextFree = c; + } else { + c->nextFree = this->freeCells->nextFree; + c->prevFree = this->freeCells; + c->nextFree->prevFree = c; + c->prevFree->nextFree = c; + } + } + } + *adr = NULL; +} + +/* *****************************************************************/ +/* Exception Management */ +/* *****************************************************************/ +/** object : exceptionManager + * shortcut : em + * + */ + +typedef picoos_char picoos_exc_msg[PICOOS_MAX_EXC_MSG_LEN]; +typedef picoos_char picoos_warn_msg[PICOOS_MAX_WARN_MSG_LEN]; + +typedef struct picoos_exception_manager +{ + picoos_int32 curExceptionCode; + picoos_exc_msg curExceptionMessage; + + picoos_uint8 curNumWarnings; + picoos_int32 curWarningCode[PICOOS_MAX_NUM_WARNINGS]; + picoos_warn_msg curWarningMessage[PICOOS_MAX_NUM_WARNINGS]; + +} picoos_exception_manager_t; + +void picoos_emReset(picoos_ExceptionManager this) +{ + this->curExceptionCode = PICO_OK; + this->curExceptionMessage[0] = '\0'; + this->curNumWarnings = 0; +} + +picoos_ExceptionManager picoos_newExceptionManager(picoos_MemoryManager mm) +{ + picoos_ExceptionManager this = (picoos_ExceptionManager) picoos_allocate( + mm, sizeof(*this)); + if (NULL != this) { + /* initialize */ + picoos_emReset(this); + } + return this; +} + +void picoos_disposeExceptionManager(picoos_MemoryManager mm, + picoos_ExceptionManager * this) +{ + if (NULL != (*this)) { + /* terminate */ + picoos_deallocate(mm, (void *)this); + } +} + +static void picoos_vSetErrorMsg(picoos_char * dst, picoos_objsize_t siz, + picoos_int16 code, picoos_char * base, const picoos_char *fmt, va_list args) +{ + picoos_uint16 bsize; + + if (NULL == base) { + switch (code) { + case PICO_EXC_NUMBER_FORMAT: + base = PICOOS_MSG_EXC_NUMBER_FORMAT; + break; + case PICO_EXC_MAX_NUM_EXCEED: + base = PICOOS_MSG_EXC_MAX_NUM_EXCEED; + break; + case PICO_EXC_NAME_CONFLICT: + base = PICOOS_MSG_EXC_NAME_CONFLICT; + break; + case PICO_EXC_NAME_UNDEFINED: + base = PICOOS_MSG_EXC_NAME_UNDEFINED; + break; + case PICO_EXC_NAME_ILLEGAL: + base = PICOOS_MSG_EXC_NAME_ILLEGAL; + break; + + /* buffer interaction */ + case PICO_EXC_BUF_OVERFLOW: + base = PICOOS_MSG_EXC_BUF_OVERFLOW; + break; + case PICO_EXC_BUF_UNDERFLOW: + base = PICOOS_MSG_EXC_BUF_UNDERFLOW; + break; + case PICO_EXC_BUF_IGNORE: + base = PICOOS_MSG_EXC_BUF_IGNORE; + break; + + /* memory allocation */ + case PICO_EXC_OUT_OF_MEM: + base = PICOOS_MSG_EXC_OUT_OF_MEM; + break; + + /* files */ + case PICO_EXC_CANT_OPEN_FILE: + base = PICOOS_MSG_EXC_CANT_OPEN_FILE; + break; + case PICO_EXC_UNEXPECTED_FILE_TYPE: + base = PICOOS_MSG_EXC_UNEXPECTED_FILE_TYPE; + break; + case PICO_EXC_FILE_CORRUPT: + base = PICOOS_MSG_EXC_FILE_CORRUPT; + break; + + case PICO_EXC_FILE_NOT_FOUND: + base = PICOOS_MSG_EXC_FILE_NOT_FOUND; + break; + + /* resources */ + case PICO_EXC_RESOURCE_BUSY: + base = PICOOS_MSG_EXC_RESOURCE_BUSY; + break; + case PICO_EXC_RESOURCE_MISSING: + base = PICOOS_MSG_EXC_RESOURCE_MISSING; + break; + + /* knowledge bases */ + case PICO_EXC_KB_MISSING: + fmt = PICOOS_MSG_EXC_KB_MISSING; + break; + + /* runtime exceptions (programming problems, usually a bug. E.g. trying to access null pointer) */ + case PICO_ERR_NULLPTR_ACCESS: + base = PICOOS_MSG_ERR_NULLPTR_ACCESS; + break; + case PICO_ERR_INVALID_HANDLE: + base = PICOOS_MSG_ERR_INVALID_HANDLE; + break; + case PICO_ERR_INVALID_ARGUMENT: + base = PICOOS_MSG_ERR_INVALID_ARGUMENT; + break; + case PICO_ERR_INDEX_OUT_OF_RANGE: + base = PICOOS_MSG_ERR_INDEX_OUT_OF_RANGE; + break; + + /* errors ("external" errors, e.g. hardware failure. Usually cannot be dealt with from inside pico.) */ + case PICO_ERR_OTHER: + base = PICOOS_MSG_ERR_OTHER; + break; + + /* other error inside pu */ + case PICO_STEP_ERROR: + base = PICOOS_MSG_ERR_PU; + break; + + /* WARNINGS */ + + /* general */ + case PICO_WARN_INCOMPLETE: + base = PICOOS_MSG_WARN_INCOMPLETE; + break; + case PICO_WARN_FALLBACK: + base = PICOOS_MSG_WARN_FALLBACK; + break; + + case PICO_WARN_OTHER: + base = PICOOS_MSG_WARN_OTHER; + break; + + /* resources */ + case PICO_WARN_KB_OVERWRITE: + base = PICOOS_MSG_WARN_KB_OVERWRITE; + break; + case PICO_WARN_RESOURCE_DOUBLE_LOAD: + base = PICOOS_MSG_WARN_RESOURCE_DOUBLE_LOAD; + break; + + /* decision trees */ + case PICO_WARN_INVECTOR: + base = PICOOS_MSG_WARN_INVECTOR; + break; + case PICO_WARN_CLASSIFICATION: + base = PICOOS_MSG_WARN_CLASSIFICATION; + break; + case PICO_WARN_OUTVECTOR: + base = PICOOS_MSG_WARN_OUTVECTOR; + break; + + /* processing units */ + case PICO_WARN_PU_IRREG_ITEM: + base = PICOOS_MSG_WARN_PU_IRREG_ITEM; + break; + case PICO_WARN_PU_DISCARD_BUF: + base = PICOOS_MSG_WARN_PU_DISCARD_BUF; + break; + + default: + base = (picoos_char *) "unknown error"; + break; + } + } + bsize = picoos_strlcpy(dst,base,siz); + if ((NULL != fmt) && (bsize < siz)) { /* there is something to add and more space to add it */ + if (bsize > 0) { + dst += bsize; + siz -= bsize; + bsize = picoos_strlcpy(dst,(picoos_char *)": ",siz); + } + if (bsize < siz) { + picopal_vslprintf((picopal_char *) dst + bsize, siz - bsize, (picopal_char *)fmt, args); + } + } +} + +void picoos_setErrorMsg(picoos_char * dst, picoos_objsize_t siz, + picoos_int16 code, picoos_char * base, const picoos_char *fmt, ...) +{ + va_list args; + va_start(args, (char *)fmt); + picoos_vSetErrorMsg(dst,siz, code, base, fmt,args); + va_end(args); +} + +/* For convenience, this function returns the resulting current exception code. The return value therefore is NOT the status of raising + * the error! */ +pico_status_t picoos_emRaiseException(picoos_ExceptionManager this, + pico_status_t exceptionCode, picoos_char * baseMessage, picoos_char * fmt, ...) +{ + va_list args; + + + if (PICO_OK == this->curExceptionCode && PICO_OK != exceptionCode) { + this->curExceptionCode = exceptionCode; + va_start(args, (char *)fmt); + picoos_vSetErrorMsg(this->curExceptionMessage,PICOOS_MAX_EXC_MSG_LEN, exceptionCode, baseMessage, fmt,args); + PICODBG_DEBUG(( + "exit with exception code=%i, exception message='%s'", + this->curExceptionCode, this->curExceptionMessage)); + + va_end(args); + + } + return this->curExceptionCode; +} + +pico_status_t picoos_emGetExceptionCode(picoos_ExceptionManager this) +{ + return this->curExceptionCode; +} + +void picoos_emGetExceptionMessage(picoos_ExceptionManager this, picoos_char * msg, picoos_uint16 maxsize) +{ + picoos_strlcpy(msg,this->curExceptionMessage,maxsize); +} + +void picoos_emRaiseWarning(picoos_ExceptionManager this, + pico_status_t warningCode, picoos_char * baseMessage, picoos_char * fmt, ...) +{ + va_list args; + if ((this->curNumWarnings < PICOOS_MAX_NUM_WARNINGS) && (PICO_OK != warningCode)) { + if (PICOOS_MAX_NUM_WARNINGS-1 == this->curNumWarnings) { + this->curWarningCode[this->curNumWarnings] = PICO_EXC_MAX_NUM_EXCEED; + picoos_strlcpy(this->curWarningMessage[this->curNumWarnings],(picoos_char *) "too many warnings",PICOOS_MAX_WARN_MSG_LEN); + } else { + this->curWarningCode[this->curNumWarnings] = warningCode; + va_start(args, (char *)fmt); + picoos_vSetErrorMsg(this->curWarningMessage[this->curNumWarnings],PICOOS_MAX_WARN_MSG_LEN, warningCode, baseMessage, fmt,args); + va_end(args); + } + this->curNumWarnings++; + } + PICODBG_DEBUG(( + "exit with code=%i and message='%s', resulting in #warnings=%i", + this->curWarningCode[this->curNumWarnings-1], + this->curWarningMessage[this->curNumWarnings-1], + this->curNumWarnings)); +} + +picoos_uint8 picoos_emGetNumOfWarnings(picoos_ExceptionManager this) +{ + return this->curNumWarnings; +} + +pico_status_t picoos_emGetWarningCode(picoos_ExceptionManager this, picoos_uint8 index) +{ + if (index < this->curNumWarnings) { + return this->curWarningCode[index]; + } else { + return PICO_OK; + } +} + +void picoos_emGetWarningMessage(picoos_ExceptionManager this, picoos_uint8 index, picoos_char * msg, picoos_uint16 maxsize) +{ + if (index < this->curNumWarnings) { + picoos_strlcpy(msg,this->curWarningMessage[index],maxsize); + } else { + msg[0] = NULLC; + } +} + + + + +/* *****************************************************************/ +/* File Access */ +/* *****************************************************************/ + +#define picoos_MagicNumber 192837465 +#define picoos_MaxBufSize 1000000 +#define picoos_MaxNrOfBuffers 1000000 +#define picoos_MaxBufLen 8192 +#define picoos_HashFuncId0 0 +#define picoos_HashTableSize0 101 +#define picoos_HashTableSize1 1731 +#define picoos_MaxHashTableSize HashTableSize1 + +#define cardinal_ptr_t picoos_uint32 * + +typedef struct picoos_buffer +{ + picoos_char * data; + int start; /* denotes the file position of the buffer beginning */ + int len; /* denotes the length of the buffer; -1 means invalid buffer */ + int pos; /* denotes the position in the buffer */ +} picoos_buffer_t; + +typedef picoos_buffer_t picoos_buffer_array_t[picoos_MaxNrOfBuffers]; +typedef picoos_int32 picoos_buffer_index_array_t[picoos_MaxNrOfBuffers]; + +/** object : File + * shortcut : f + * + */ +typedef struct picoos_file +{ + picoos_FileName name; + picoos_uint8 binary; + picoos_uint8 write; + + picopal_File nf; + + picoos_uint32 lFileLen; + picoos_uint32 lPos; + + picoos_File next; + picoos_File prev; + +} picoos_file_t; + +picoos_File picoos_newFile(picoos_MemoryManager mm) +{ + picoos_File this = (picoos_File) picoos_allocate(mm, sizeof(*this)); + if (NULL != this) { + /* initialize */ + } + return this; +} + +void picoos_disposeFile(picoos_MemoryManager mm, picoos_File * this) +{ + if (NULL != (*this)) { + /* terminate */ + picoos_deallocate(mm, (void *)this); + } +} + + +/* ************************************************************ + * low-level file operations + **************************************************************/ + +static picoos_int32 os_min(const picoos_int32 x, const picoos_int32 y) +{ + return (x < y) ? x : y; +} + +/* + static picoos_uint8 LReadChar (picoos_File f, picoos_char * ch); + + + static picoos_uint8 LSetPos (picoos_File f, unsigned int pos); + + + static picoos_uint8 LGetPos (picoos_File f, picoos_uint32 * pos); + + + static picoos_uint8 LEof (picoos_File f); + */ + +static picoos_bool LOpen(picoos_Common g, picoos_File * f, + picoos_char fileName[], picopal_access_mode mode) +{ + picoos_bool done = TRUE; + + *f = picoos_newFile(g->mm); + picopal_strcpy((*f)->name, fileName); + (*f)->write = ((mode == PICOPAL_TEXT_WRITE) || (mode + == PICOPAL_BINARY_WRITE)); + (*f)->binary = (mode + == PICOPAL_BINARY_WRITE); + (*f)->next = NULL; + (*f)->prev = NULL; + (*f)->nf = picopal_get_fnil(); + (*f)->lFileLen = 0; + (*f)->lPos = 0; + if (picopal_strlen((*f)->name)) { + (*f)->nf = picopal_fopen((*f)->name, mode); + done = !(picopal_is_fnil((*f)->nf)); + if (done) { + (*f)->lFileLen = picopal_flength((*f)->nf); + } + } + if (done) { + (*f)->next = g->fileList; + if (g->fileList != NULL) { + g->fileList->prev = (*f); + } + g->fileList = (*f); + } else { + picoos_disposeFile(g->mm, f); + (*f) = NULL; + } + return done; +} + +static picoos_bool LClose(picoos_Common g, picoos_File * f) +{ + + picoos_bool done; + + if (((*f) != NULL)) { + done = (PICO_OK == picopal_fclose((*f)->nf)); + if (((*f)->next != NULL)) { + (*f)->next->prev = (*f)->prev; + } + if (((*f)->prev != NULL)) { + (*f)->prev->next = (*f)->next; + } else { + g->fileList = (*f)->next; + } + picoos_disposeFile(g->mm, f); + + done = TRUE; + } else { + done = FALSE; + } + return done; + +} + +/* caller must ensure that bytes[] has at least len allocated bytes */ +static picoos_bool LReadBytes(picoos_File f, picoos_uint8 bytes[], + picoos_uint32 * len) +{ + picoos_bool done; + picoos_int32 res; + + PICODBG_TRACE(("trying to read %i bytes",*len)); + if ((f != NULL)) { + res = picopal_fread_bytes(f->nf, (void *) &bytes[(0)], 1, (*len)); + PICODBG_TRACE(("res = %i",res)); + if (res < 0) { /* non-ansi */ + (*len) = 0; + done = FALSE; + } else if (((picoos_uint32)res != (*len))) { + (*len) = res; + done = FALSE; + } else { + done = TRUE; + } + f->lPos = (f->lPos + (*len)); + } else { + (*len) = 0; + done = FALSE; + } + return done; +} + + static picoos_bool LWriteBytes(picoos_File f, const picoos_char bytes[], int * len) { + picoos_bool done; + int res; + /*int n; + void * bptr; */ + + if (f != NULL) { + res = picopal_fwrite_bytes(f->nf, (void *) bytes, 1, *len); + if ((res < 0)) { + (*len) = 0; + done = FALSE; + } else if ((res != (*len))) { + (*len) = res; + done = FALSE; + } else { + done = TRUE; + } + f->lPos = (f->lPos + (unsigned int) (*len)); + if ((f->lPos > f->lFileLen)) { + f->lFileLen = f->lPos; + } + } else { + (*len) = 0; + done = FALSE; + } + return done; +} + + +static picoos_bool LSetPos(picoos_File f, unsigned int pos) +{ + + picoos_bool done; + + if ((f != NULL)) { + if (pos == f->lPos) { + done = TRUE; + } else { + done = (PICO_OK == picopal_fseek(f->nf, pos, PICOPAL_SEEK_SET)); + if (done) { + f->lPos = pos; + } + } + } else { + done = FALSE; + } + return done; +} + +static picoos_bool LGetPos(picoos_File f, picoos_uint32 * pos) +{ + picoos_bool done = TRUE; + if ((f != NULL)) { + (*pos) = f->lPos; + } else { + done = FALSE; + (*pos) = 0; + } + return done; + +} + +static picoos_bool LEof(picoos_File f) +{ + picoos_bool isEof; + + if ((f != NULL)) { + isEof = picopal_feof(f->nf); + } else { + isEof = TRUE; + } + return isEof; + +} + +/* **************************************************************************************/ + + + +/* read a given string 'str' from file. If no match was found, the read position is advanced until and including the first + * non-matching character */ +static picoos_bool picoos_StrRead (picoos_File f, picoos_char str[]) +{ + picoos_uint32 i = 0; + picoos_bool done = TRUE; + picoos_char b; + + while (done && (str[i] != NULLC)) { + done = done && picoos_ReadByte(f,(picoos_char *)&b); + done = done && (b == str[i]); + i++; + } + return done; +} + +/* write 'str' to file */ +static picoos_bool picoos_WriteStr (picoos_File f, picoos_char str[]) +{ + picoos_uint32 i = 0; + picoos_bool done = TRUE; + + while (done && (str[i] != NULLC)) { + done = done && picoos_WriteByte(f,str[i]); + i++; + } + return done; +} + + + +/* **** Sequential binary file access ******/ + +/* Remark: 'ReadByte', 'ReadBytes' and 'ReadVar' may be mixed; + 'WriteByte', 'WriteBytes' and 'WriteVar' may be mixed. */ + +/* Open existing binary file for read access. Reading is buffered + * with 'nrOfBufs' buffers of size 'bufSize'. If 'nrOfBufs' or + * 'bufSize' is 0 reading is not buffered. + * If 'key' is not empty, the file is decrypted with 'key'. + * If the opened file is in an encrypted archive file, it + */ +picoos_uint8 picoos_OpenBinary(picoos_Common g, picoos_File * f, + picoos_char fileName[]) +{ + return LOpen(g, f, fileName, PICOPAL_BINARY_READ); +} + + +/* Read next byte from file 'f'. */ +picoos_bool picoos_ReadByte(picoos_File f, picoos_uint8 * by) +{ + picoos_uint32 n = 1; + + return picoos_ReadBytes(f, by, &n) && (n == 1); + +} + +/* Read next 'len' bytes from 'f' into 'bytes'; 'len' returns the + number of bytes actually read (may be smaller than requested + length if at end of file). bytes[] must be big enough to hold at least len bytes. +*/ +picoos_bool picoos_ReadBytes(picoos_File f, picoos_uint8 bytes[], + picoos_uint32 * len) +{ + picoos_bool done = TRUE; + /* unsigned int origPos; */ + + if ((f != NULL)) { + done = LReadBytes(f, bytes, len); + /*if ((f->keyLen > 0)) { + DecryptBytes(f->key,picoos_MaxKeyLen,f->keyLen,origPos,bytes,(*len)); + }*/ + } + + return done; +} + + +/* Create new binary file. + If 'key' is not empty, the file is encrypted with 'key'. */ +picoos_bool picoos_CreateBinary(picoos_Common g, picoos_File * f, + picoos_char fileName[]) +{ + return LOpen(g, f, fileName, PICOPAL_BINARY_WRITE); + +} + + +picoos_uint8 picoos_WriteByte(picoos_File f, picoos_char by) +{ + int n = 1; + + return picoos_WriteBytes(f, (picoos_char *) &by, &n); +} + + +/* Writes 'len' bytes from 'bytes' onto file 'f'; 'len' returns + the number of bytes actually written. */ +picoos_bool picoos_WriteBytes(picoos_File f, const picoos_char bytes[], picoos_int32 * len) { + picoos_bool done = FALSE; + + if (f != NULL) { + done = LWriteBytes(f, bytes, len); + } + + return done; +} + + + +/* Close previously opened binary file. */ +picoos_uint8 picoos_CloseBinary(picoos_Common g, picoos_File * f) +{ + return LClose(g, f); + +} + +/* **************************************************************************************/ +/* *** general routines *****/ + + +/* Returns whether end of file was encountered in previous + read operation. */ +picoos_bool picoos_Eof(picoos_File f) +{ + if ((NULL != f)) { + return LEof(f); + } else { + return TRUE; + } + +} + +/* sets the file pointer to + 'pos' bytes from beginning (first byte = byte 0). This + routine should only be used for binary files. */ +picoos_bool picoos_SetPos(picoos_File f, picoos_int32 pos) +{ + picoos_bool done = TRUE; + if ((NULL != f)) { + done = LSetPos(f, pos); + } else { + done = FALSE; + } + return done; + +} + +/* Get position from file 'f'. */ +picoos_bool picoos_GetPos(picoos_File f, picoos_uint32 * pos) +{ + if (NULL != f) { + /* if (f->bFile) { + (*pos) = BGetPos(f); + } else { */ + (*pos) = LGetPos(f, pos); + /* } */ + return TRUE; + } else { + (*pos) = 0; + return FALSE; + } +} + +/* Returns the length of the file in bytes. */ +picoos_bool picoos_FileLength(picoos_File f, picoos_uint32 * len) +{ + + if (NULL != f) { + *len = f->lFileLen; + return TRUE; + } else { + *len = 0; + return FALSE; + } +} + +/* Return full name of file 'f'. maxsize is the size of 'name[]' in bytes */ +picoos_bool picoos_Name(picoos_File f, picoos_char name[], picoos_uint32 maxsize) +{ + picoos_bool done = TRUE; + + if (NULL != f) { + done = (picoos_strlcpy(name, f->name,maxsize) < maxsize); + } else { + name[0] = (picoos_char)NULLC; + done = FALSE; + } + + return done; +} + +/* Returns whether file 'name' exists or not. */ +picoos_bool picoos_FileExists(picoos_Common g, picoos_char name[]) +{ + picoos_File f; + + if (picoos_OpenBinary(g, & f,name)) { + picoos_CloseBinary(g, & f); + return TRUE; + } else { + return FALSE; + } +} + + +/* ******************************************************************/ +/* Array conversion operations: all procedures convert 'nrElems' values from + 'src' starting with index 'srcStartInd' into corresponding (possibly + rounded) values in 'dst' starting at 'dstStartInd'. */ + +/* taking pi to be le, these are just the array versions of read_mem_pi_*int16 */ +typedef picoos_uint8 two_byte_t[2]; + +static void arr_conv_le_int16 (picoos_uint8 src[], picoos_uint32 srcShortStartInd, picoos_uint32 nrElems, picoos_int16 dst[], picoos_uint32 dstStartInd) +{ + two_byte_t * src_p = (two_byte_t *) (src + (srcShortStartInd * 2)); + picoos_int16 * dst_p = dst + dstStartInd; + picoos_uint32 i; + + for (i=0; i>8); + dst_p++; + } +} + +/* *****************************************************************/ +/* Sampled Data Files */ +/* *****************************************************************/ + +#define PICOOS_SDF_BUF_LEN 1024 + +#define PICOOS_INT16_MIN -32768 +#define PICOOS_INT16_MAX 32767 +#define PICOOS_UINT16_MAX 0xffff +#define PICOOS_INT32_MIN -2147483648 +#define PICOOS_INT32_MAX 2147483647 +#define PICOOS_UINT32_MAX 0xffffffff + +/** object : SDFile + * shortcut : sdf + * + */ +/* typedef struct picoos_sd_file * picoos_SDFile */ +typedef struct picoos_sd_file +{ + picoos_uint32 sf; + wave_file_type_t fileType; /* (acoustic) wav, au, raw, other */ + picoos_uint32 hdrSize; + picoos_encoding_t enc; + picoos_File file; + picoos_uint32 nrFileSamples; + picoos_int16 buf[PICOOS_SDF_BUF_LEN]; + picoos_int32 bufPos; + picoos_uint8 bBuf[2*PICOOS_SDF_BUF_LEN]; + picoos_bool aborted; +} picoos_sd_file_t; + + +/* Tries to read wav header at beginning of file 'f'; + returns sampling rate 'sf', encoding type 'enc', + nr of samples in file 'nrSamples', header size 'hdrSize', + and byte order 'bOrder'; returns whether a supported + wav header and format was found. */ +static picoos_bool picoos_readWavHeader(picoos_File f, picoos_uint32 * sf, + picoos_encoding_t * enc, picoos_uint32 * nrSamples, + picoos_uint32 * hdrSize) { + picoos_uint16 n16; + picoos_uint32 n32; + picoos_uint16 formatTag; + picoos_uint32 sampleRate; + picoos_uint32 bytesPerSec; + picoos_uint16 blockAlign; + picoos_uint16 sampleSize; + picoos_uint32 dataLength; + picoos_uint32 fileLen; + picoos_uint32 nrFileSamples; + picoos_bool done; + + + picoos_SetPos(f, 0); + picoos_FileLength(f, &fileLen); + done = picoos_StrRead(f, (picoos_char *) "RIFF"); + done = done && (PICO_OK == picoos_read_le_uint32(f, &n32)); /* length of riff chunk, unused */ + done = done && picoos_StrRead(f, (picoos_char *) "WAVE"); + done = done && picoos_StrRead(f, (picoos_char *) "fmt "); + done = done && (PICO_OK == picoos_read_le_uint32(f, &n32)); /* length of fmt chunk in bytes; must be 16 */ + done = done && (n32 == 16); + done = done && (PICO_OK == picoos_read_le_uint16(f, &formatTag)); + done = done && (PICO_OK == picoos_read_le_uint16(f, &n16)); /* number of channels; must be mono */ + done = done && (n16 == 1); + done = done && (PICO_OK == picoos_read_le_uint32(f, &sampleRate)); + done = done && (PICO_OK == picoos_read_le_uint32(f, &bytesPerSec)); + done = done && (PICO_OK == picoos_read_le_uint16(f, &blockAlign)); + done = done && (PICO_OK == picoos_read_le_uint16(f, &sampleSize)); + done = done && picoos_StrRead(f, (picoos_char *) "data"); + done = done && (PICO_OK == picoos_read_le_uint32(f, &dataLength)); /* length of data chunk in bytes */ + (*hdrSize) = 44; + if (done) { + (*sf) = sampleRate; + (*nrSamples) = 0; + switch (formatTag) { + case FORMAT_TAG_LIN: + (*enc) = PICOOS_ENC_LIN; + done = ((blockAlign == 2) && (sampleSize == 16)); + (*nrSamples) = (dataLength / 2); + nrFileSamples = ((fileLen - (*hdrSize)) / 2); + break; + case FORMAT_TAG_ULAW: + (*enc) = PICOOS_ENC_ULAW; + done = ((blockAlign == 1) && (sampleSize == 8)); + (*nrSamples) = dataLength; + nrFileSamples = (fileLen - (*hdrSize)); + break; + case FORMAT_TAG_ALAW: + (*enc) = PICOOS_ENC_ALAW; + done = ((blockAlign == 1) && (sampleSize == 8)); + (*nrSamples) = dataLength; + nrFileSamples = (fileLen - (*hdrSize)); + break; + default: + done = FALSE; + break; + } + if (!done) { + /* communicate "unsupported format" */ + PICODBG_WARN(("unsupported wav format")); + } else { + if (nrFileSamples != (*nrSamples)) { + /* warn "inconsistent number of samples" */ + PICODBG_WARN(("inconsistent number of samples in wav file: %d vs. %d",nrFileSamples,(*nrSamples))); + (*nrSamples) = nrFileSamples; + } + } + } + return done; +} + + + +extern picoos_bool picoos_sdfOpenIn(picoos_Common g, picoos_SDFile * sdFile, + picoos_char fileName[], picoos_uint32 * sf, picoos_encoding_t * enc, + picoos_uint32 * numSamples) +{ + picoos_bool done = FALSE; + picoos_sd_file_t * sdf = NULL; + wave_file_type_t fileType = FILE_TYPE_OTHER; + + (*sf) = 0; + (*numSamples) = 0; + (*enc) = PICOOS_ENC_LIN; + (*sdFile) = NULL; + + sdf = picoos_allocate(g->mm,sizeof(picoos_sd_file_t)); + if (NULL == sdf) { + picoos_emRaiseWarning(g->em,PICO_EXC_OUT_OF_MEM,NULL,NULL); + return FALSE; + } + + /* buffered access not supported, yet */ + if (picoos_OpenBinary(g,&(sdf->file),fileName)) { + if (picoos_has_extension(fileName,(picoos_char *) ".wav")) { + fileType = FILE_TYPE_WAV; + done = picoos_readWavHeader(sdf->file,&(sdf->sf),&(sdf->enc),&(sdf->nrFileSamples),&(sdf->hdrSize)); + } else { + /* we prefer not to treat other formats, rather than treat it as raw */ + /* fileType = FILE_TYPE_RAW; */ + fileType = FILE_TYPE_OTHER; + done = FALSE; + } + + if (FILE_TYPE_OTHER == fileType) { + picoos_emRaiseWarning(g->em,PICO_EXC_UNEXPECTED_FILE_TYPE,(picoos_char *)"unsupported filename suffix",NULL); + } else if (!done) { + picoos_emRaiseWarning(g->em,PICO_EXC_UNEXPECTED_FILE_TYPE,(picoos_char *)"non-conforming header",NULL); + } else { + (*numSamples) = sdf->nrFileSamples; + (*sf) = sdf->sf; + (*enc) = sdf->enc; + /* check whether sd file properties are supported */ + if (PICOOS_ENC_LIN != sdf->enc) { + done = FALSE; + picoos_emRaiseWarning(g->em,PICO_EXC_UNEXPECTED_FILE_TYPE,NULL,(picoos_char *)"encoding not supported"); + } + if (SAMPLE_FREQ_16KHZ != sdf->sf) { + done = FALSE; + picoos_emRaiseWarning(g->em,PICO_EXC_UNEXPECTED_FILE_TYPE,NULL,(picoos_char *)"sample frequency not supported"); + } + (*sdFile) = sdf; + } + if (!done){ + picoos_CloseBinary(g,&(sdf->file)); + } + } else { + picoos_emRaiseException(g->em,PICO_EXC_CANT_OPEN_FILE,NULL,NULL); + } + if (!done) { + picoos_deallocate(g->mm,(void *)&sdf); + (*sdFile) = NULL; + } + return done; +} + + +static void picoos_sdfLoadSamples(picoos_SDFile sdFile, + picoos_uint32 * nrSamples) { + picoos_uint32 len; + picoos_sd_file_t * sdf = sdFile; + + switch (sdFile->enc) { + case PICOOS_ENC_LIN: + if ((*nrSamples) > PICOOS_SDF_BUF_LEN) { + (*nrSamples) = PICOOS_SDF_BUF_LEN; + } + len = 2 * (*nrSamples); + picoos_ReadBytes(sdf->file, sdf->bBuf, &len); + (*nrSamples) = len / 2; + arr_conv_le_int16(sdf->bBuf, 0, (*nrSamples), sdf->buf, 0); + break; + /* @todo : may be useful */ + case PICOOS_ENC_ULAW: + case PICOOS_ENC_ALAW: + default: + (*nrSamples) = 0; + } + +} + +extern picoos_bool picoos_sdfGetSamples ( + picoos_SDFile sdFile, + picoos_uint32 start, + picoos_uint32 * nrSamples, + picoos_int16 samples[]) +{ + picoos_uint32 b; + picoos_uint32 rem; + picoos_uint32 n; + picoos_uint32 i; + picoos_uint32 j; + picoos_bool done = FALSE; + + if (NULL == sdFile) { + (*nrSamples) = 0; + } else { + if (start >= sdFile->nrFileSamples) { + if (start > sdFile->nrFileSamples) { + PICODBG_WARN(("start has to be <= sdFile->nrFileSamples")); + } + (*nrSamples) = 0; + } else { + if (((start + (*nrSamples)) > sdFile->nrFileSamples)) { + (*nrSamples) = (sdFile->nrFileSamples - start); + } + if (sdFile->enc == PICOOS_ENC_LIN) { + b = 2; + } else { + b = 1; + } + picoos_SetPos(sdFile->file,(sdFile->hdrSize + (b * start))); + j = 0; + rem = (*nrSamples); + n = rem; + while ((rem > 0) && (n > 0)) { + /* set n=min(rem,buffer_length) and try loading next n samples */ + n = (rem < PICOOS_SDF_BUF_LEN) ? rem : PICOOS_SDF_BUF_LEN; + picoos_sdfLoadSamples(sdFile, &n); + /* n may be smaller now */ + for (i = 0; i < n; i++) { + samples[j] = sdFile->buf[i]; + j++; + } + rem -= n; + start += n; + } + (*nrSamples) = j; + done = ((*nrSamples) > 0); + } + } + return done; +} + + +extern picoos_bool picoos_sdfCloseIn (picoos_Common g, picoos_SDFile * sdFile) +{ + if (NULL != (*sdFile)) { + picoos_CloseBinary(g,&((*sdFile)->file)); + picoos_deallocate(g->mm,(void *)sdFile); + } + return TRUE; +} + + +static picoos_bool picoos_writeWavHeader(picoos_File f, picoos_uint32 sf, + picoos_encoding_t enc, picoos_uint32 nrSamples, + picoos_uint32 * hdrSize) { + picoos_uint16 formatTag = FORMAT_TAG_LIN; + picoos_uint32 sampleRate; + picoos_uint32 bytesPerSec; + picoos_uint32 bytesPerSample = 2; + picoos_uint16 blockAlign; + picoos_uint16 sampleSize = 16; + picoos_uint32 dataLength; + picoos_bool done = TRUE; + + picoos_SetPos(f, 0); + + switch (enc) { + case PICOOS_ENC_LIN: + formatTag = FORMAT_TAG_LIN; + bytesPerSample = 2; + sampleSize = 16; + break; + case PICOOS_ENC_ULAW: + formatTag = FORMAT_TAG_ULAW; + bytesPerSample = 1; + sampleSize = 8; + break; + case PICOOS_ENC_ALAW: + formatTag = FORMAT_TAG_ALAW; + bytesPerSample = 1; + sampleSize = 8; + break; + default: + done = FALSE; + break; + } + + bytesPerSec = (sf * bytesPerSample); + blockAlign = bytesPerSample; + sampleRate = sf; + dataLength = (bytesPerSample * nrSamples); + done = done && picoos_WriteStr(f,(picoos_char *)"RIFF"); + done = done && picoos_write_le_uint32(f,dataLength + 36); + done = done && picoos_WriteStr(f,(picoos_char *)"WAVE"); + done = done && picoos_WriteStr(f,(picoos_char *)"fmt "); + done = done && picoos_write_le_uint32(f,16); + done = done && picoos_write_le_uint16(f,formatTag); + done = done && picoos_write_le_uint16(f,1); + done = done && picoos_write_le_uint32(f,sampleRate); + done = done && picoos_write_le_uint32(f,bytesPerSec); + done = done && picoos_write_le_uint16(f,blockAlign); + done = done && picoos_write_le_uint16(f,sampleSize); + done = done && picoos_WriteStr(f,(picoos_char *)"data"); + done = done && picoos_write_le_uint32(f,dataLength); + (*hdrSize) = 44; + return done; +} + + +#define DummyLen 100000000 + +extern picoos_bool picoos_sdfOpenOut(picoos_Common g, picoos_SDFile * sdFile, + picoos_char fileName[], int sf, picoos_encoding_t enc) +{ + picoos_bool done = TRUE; + picoos_sd_file_t * sdf = NULL; + + (*sdFile) = NULL; + sdf = picoos_allocate(g->mm, sizeof(picoos_sd_file_t)); + if (NULL == sdf) { + picoos_emRaiseWarning(g->em, PICO_EXC_OUT_OF_MEM, NULL, NULL); + return FALSE; + } + sdf->sf = sf; + sdf->enc = enc; + /* check whether sd file properties are supported */ + if (PICOOS_ENC_LIN != sdf->enc) { + done = FALSE; + picoos_emRaiseWarning(g->em, PICO_EXC_UNEXPECTED_FILE_TYPE, NULL, + (picoos_char *) "encoding not supported"); + } + if (SAMPLE_FREQ_16KHZ != sdf->sf) { + done = FALSE; + picoos_emRaiseWarning(g->em, PICO_EXC_UNEXPECTED_FILE_TYPE, NULL, + (picoos_char *) "sample frequency not supported"); + } + if (done) { + sdf->nrFileSamples = 0; + sdf->bufPos = 0; + sdf->aborted = FALSE; + if (picoos_CreateBinary(g, &(sdf->file), fileName)) { + if (picoos_has_extension(fileName, (picoos_char *) ".wav")) { + sdf->fileType = FILE_TYPE_WAV; + done = picoos_writeWavHeader(sdf->file, sdf->sf, sdf->enc, + DummyLen, &(sdf->hdrSize)); + } else { + /* we prefer not to treat other formats, rather than treat it as raw */ + /* fileType = FILE_TYPE_RAW; */ + sdf->fileType = FILE_TYPE_OTHER; + done = FALSE; + } + + if (FILE_TYPE_OTHER == sdf->fileType) { + picoos_emRaiseWarning(g->em, PICO_EXC_UNEXPECTED_FILE_TYPE, + (picoos_char *) "unsupported filename suffix", NULL); + } else if (!done) { + picoos_emRaiseWarning(g->em, PICO_EXC_UNEXPECTED_FILE_TYPE, + (picoos_char *) "non-conforming header", NULL); + } else { + (*sdFile) = sdf; + } + if (!done) { + picoos_CloseBinary(g, &(sdf->file)); + } + } else { + picoos_emRaiseException(g->em, PICO_EXC_CANT_OPEN_FILE, NULL, NULL); + } + } + if (!done) { + picoos_deallocate(g->mm, (void *) &sdf); + (*sdFile) = NULL; + } + return done; +} + +static picoos_bool picoos_sdfFlushOutBuf(picoos_SDFile sdFile) +{ + picoos_bool done = FALSE; + picoos_int32 len; + picoos_int32 nrSamples; + + if (!(sdFile->aborted)) { + nrSamples = sdFile->bufPos; + switch (sdFile->enc) { + case PICOOS_ENC_LIN: + arr_conv_int16_le(sdFile->buf, 0, nrSamples, sdFile->bBuf, 0); + len = (nrSamples * 2); + done = picoos_WriteBytes(sdFile->file, sdFile->bBuf, &len) + && ((nrSamples * 2) == len); + break; + case PICOOS_ENC_ULAW: + case PICOOS_ENC_ALAW: + default: + nrSamples = 0; + break; + } + sdFile->nrFileSamples = (sdFile->nrFileSamples + nrSamples); + } + + sdFile->bufPos = 0; + return done; +} + +extern picoos_bool picoos_sdfFlushOutput(picoos_SDFile sdFile) +{ + if ((sdFile != NULL) && !(sdFile->aborted) && (sdFile->bufPos > 0)) { + return picoos_sdfFlushOutBuf(sdFile); + } + return TRUE; +} + + + +extern picoos_bool picoos_sdfPutSamples (picoos_SDFile sdFile, picoos_uint32 nrSamples, picoos_int16 samples[]) +{ + picoos_uint32 i; + picoos_int32 s; + picoos_bool done = FALSE; + + if ((sdFile != NULL) && !(sdFile->aborted)) { + done = TRUE; + for (i = 0; i < nrSamples; i++) { + s = samples[i]; + if ((s > PICOOS_INT16_MAX)) { + s = PICOOS_INT16_MAX; + } else if (s < PICOOS_INT16_MIN) { + s = PICOOS_INT16_MIN; + } + sdFile->buf[sdFile->bufPos++] = s; + if (sdFile->bufPos >= PICOOS_SDF_BUF_LEN) { + done = picoos_sdfFlushOutBuf(sdFile); + } + } + } else { + done = FALSE; + } + return done; +} + + +extern picoos_bool picoos_sdfCloseOut (picoos_Common g, picoos_SDFile * sdFile) +{ + + picoos_bool done = TRUE; + picoos_uint32 hdrSize; + + if (NULL != (*sdFile)) { + if (!((*sdFile)->aborted) && ((*sdFile)->bufPos > 0)) { + done = picoos_sdfFlushOutBuf(*sdFile); + } + if (FILE_TYPE_WAV == (*sdFile)->fileType) { + done = picoos_writeWavHeader((*sdFile)->file, (*sdFile)->sf, + (*sdFile)->enc, (*sdFile)->nrFileSamples, &hdrSize); + } + done = picoos_CloseBinary(g, &((*sdFile)->file)); + picoos_deallocate(g->mm, (void *) sdFile); + } + return done; +} + + +/* *****************************************************************/ +/* FileHeader */ +/* *****************************************************************/ + + + +pico_status_t picoos_clearHeader(picoos_FileHeader header) +{ + picoos_uint8 i; + for (i=0; i < PICOOS_MAX_NUM_HEADER_FIELDS; i++) { + header->field[i].key[0] = NULLC; + header->field[i].value[0] = NULLC; + header->field[i].op = PICOOS_FIELD_IGNORE; + } + header->numFields = 0; + return PICO_OK; +} + +pico_status_t picoos_setHeaderField(picoos_FileHeader header, + picoos_uint8 index, picoos_char * key, picoos_char * value, + picoos_compare_op_t op) +{ + if (index >= header->numFields) { + return PICO_ERR_INDEX_OUT_OF_RANGE; + } + header->field[index].op = op; + if ((picoos_strlcpy(header->field[index].key, key, + PICOOS_MAX_FIELD_STRING_LEN) < PICOOS_MAX_FIELD_STRING_LEN) + && (picoos_strlcpy(header->field[index].value, value, + PICOOS_MAX_FIELD_STRING_LEN)) < PICOOS_MAX_FIELD_STRING_LEN) { + return PICO_OK; + } else { + return PICO_ERR_INDEX_OUT_OF_RANGE; + } +} + + +/* caller has to make sure allocated space at key and value are large enough to hold a picoos_field_string */ +pico_status_t picoos_getHeaderField(picoos_FileHeader header, picoos_uint8 index, picoos_field_string_t key, picoos_field_string_t value, picoos_compare_op_t * op) +{ + if (index >= header->numFields) { + return PICO_ERR_INDEX_OUT_OF_RANGE; + } + *op = header->field[index].op; + if ((picoos_strlcpy(key,header->field[index].key, + PICOOS_MAX_FIELD_STRING_LEN) < PICOOS_MAX_FIELD_STRING_LEN) + && (picoos_strlcpy(value,header->field[index].value, + PICOOS_MAX_FIELD_STRING_LEN)) < PICOOS_MAX_FIELD_STRING_LEN) { + return PICO_OK; + } else { + return PICO_ERR_INDEX_OUT_OF_RANGE; + } + return PICO_OK; +} + + +/* check whether 'str' of length strlen matches contents in circular buffer buf, located in the first strlen bytes and ending + * position bufpos. */ +static picoos_uint8 os_matched( picoos_char * str, picoos_uint32 strlen, picoos_char * buf, picoos_int32 bufpos) { + picoos_int32 i = strlen-1; + while (i >= 0 && buf[bufpos] == str[i]) { + i--; + bufpos--; + if (bufpos < 0) { + bufpos = strlen-1; + } + } + return (i<0); +} + +pico_status_t picoos_getSVOXHeaderString(picoos_char * str, picoos_uint8 * len, picoos_uint32 maxlen) +{ + picoos_char * ch; + *len = picoos_strlcpy(str,picoos_SVOXFileHeader,maxlen); + if (*len < maxlen) { + ch = str; + /* SVOX header is made less readable */ + while (*ch) { + *ch -= ' '; + ch++; + } + return PICO_OK; + } else { + return PICO_ERR_OTHER; + } +} + +pico_status_t picoos_readPicoHeader(picoos_File f, picoos_uint32 * headerlen) +{ + picoos_char str[32]; + picoos_char buf[32]; + picoos_uint8 strlen, bufpos; + picoos_uint32 n; + picoos_uint8 done; + + picoos_getSVOXHeaderString(str,&strlen,32); + /* search for svox header somewhere near the file start. This allows for initial + * non-svox-header bytes for a customer-specific header and/or filling bytes for alignment */ + *headerlen = 0; + /* read in initial chunk of length strlen */ + n = strlen; + done = picoos_ReadBytes(f,(picoos_uint8 *)buf,&n) && (n == strlen); + if (done) { + *headerlen = n; + bufpos = strlen-1; /* last legal buf position */ + done = os_matched(str,strlen,buf,bufpos); + while (!done && *headerlen < PICO_MAX_FOREIGN_HEADER_LEN) { + n = 1; + bufpos = (bufpos + 1) % strlen; + done = picoos_ReadBytes(f,(picoos_uint8 *)buf+bufpos,&n) && 1 == n; + done = done && os_matched(str,strlen,buf,bufpos); + headerlen++; + } + } + if (done) { + return PICO_OK; + } else { + return PICO_EXC_UNEXPECTED_FILE_TYPE; + } +} + +picoos_uint8 picoos_get_str (picoos_char * fromStr, picoos_uint32 * pos, picoos_char * toStr, picoos_objsize_t maxsize) +{ + picoos_uint8 i = 0; + /* skip non-printables */ + + while ((fromStr[*pos] != NULLC) && (fromStr[*pos] <= ' ')) { + (*pos)++; + } + /* copy printable portion */ + while ((fromStr[*pos] != NULLC) && (fromStr[*pos] > ' ') && (i < maxsize-1)) { + toStr[i++] = fromStr[(*pos)++]; + } + toStr[i] = NULLC; + return (i > 0) && (fromStr[*pos] <= ' '); +} + +pico_status_t picoos_hdrParseHeader(picoos_FileHeader header, picoos_header_string_t str) +{ + picoos_uint32 curpos = 0; + picoos_uint8 i, numFields; + + + /* read number of fields */ + numFields = str[curpos++]; + numFields = os_min(numFields,PICOOS_MAX_NUM_HEADER_FIELDS); + /* read in all field pairs */ + PICODBG_DEBUG(("number of fields = %i", numFields)); + for (i = 0; i < numFields; i++) { + picoos_get_str(str,&curpos,header->field[i].key,PICOOS_MAX_FIELD_STRING_LEN); + picoos_get_str(str,&curpos,header->field[i].value,PICOOS_MAX_FIELD_STRING_LEN); + } + return PICO_OK; +} + + + + + +/* **************************************************************************/ +/* Read little-endian / platform-independent integers from file or memory */ +/* **************************************************************************/ + +/* read little-endian */ +pico_status_t picoos_read_le_uint16 (picoos_File file, picoos_uint16 * val) +{ + picoos_uint8 by[2]; + picoos_uint32 n = 2; + if (picoos_ReadBytes(file, by, &n) && 2 == n) { + /* little-endian */ + *val = (picoos_uint16) by[1] << 8 | (picoos_uint16) by[0]; + return PICO_OK; + } else { + *val = 0; + return PICO_ERR_OTHER; + } +} + +pico_status_t picoos_read_le_int16 (picoos_File file, picoos_int16 * val) +{ + return picoos_read_le_uint16(file, (picoos_uint16 *)val); +} + +pico_status_t picoos_read_le_uint32 (picoos_File file, picoos_uint32 * val) +{ + picoos_uint8 by[4]; + picoos_uint32 n = 4; + if (picoos_ReadBytes(file, by, &n) && (4 == n)) { + /* little-endian */ + PICODBG_TRACE(("reading uint 32: %i %i %i %i", + by[0], by[1], by[2], by[3])); + *val = (((picoos_uint32) by[3] << 8 | (picoos_uint32) by[2]) << 8 | (picoos_uint32) by[1]) << 8 | (picoos_uint32) by[0]; + PICODBG_TRACE(("uint 32: %i %i %i %i corresponds %i", + by[0], by[1], by[2], by[3], *val)); + return PICO_OK; + } else { + *val = 0; + return PICO_ERR_OTHER; + } +} + +/* platform-independent */ +/* our convention is that pi is little-endian. */ + +/** @todo : direct implementation if too slow */ + +pico_status_t picoos_read_pi_uint16 (picoos_File file, picoos_uint16 * val) +{ + return picoos_read_le_uint16(file,val); +} + +pico_status_t picoos_read_pi_uint32 (picoos_File file, picoos_uint32 * val) +{ + return picoos_read_le_uint32(file, val); +} + +pico_status_t picoos_read_pi_int32 (picoos_File file, picoos_int32 * val) +{ + return picoos_read_le_uint32(file, (picoos_uint32 *)val); +} + +/* read pi from memory */ + +pico_status_t picoos_read_mem_pi_uint16 (picoos_uint8 * data, picoos_uint32 * pos, picoos_uint16 * val) +{ + picoos_uint8 * by = data + *pos; + + /* little-endian */ + *val = (picoos_uint16) by[1] << 8 | (picoos_uint16) by[0]; + (*pos) += 2; + return PICO_OK; +} + +pico_status_t picoos_read_mem_pi_uint32 (picoos_uint8 * data, picoos_uint32 * pos, picoos_uint32 * val) +{ + picoos_uint8 * by = data + *pos; + + /* little-endian */ + *val = (((picoos_uint32) by[3] << 8 | (picoos_uint32) by[2]) << 8 | (picoos_uint32) by[1]) << 8 | (picoos_uint32) by[0]; + (*pos) += 4; + return PICO_OK; +} + +/* **************************************************************************/ +/* Write little-endian / platform-independent integers into file or memory */ +/* **************************************************************************/ +/* write little-endian */ +pico_status_t picoos_write_le_uint16 (picoos_File file, picoos_uint16 val) +{ + picoos_int32 len = 2; + picoos_uint8 by[2]; + + by[0] = (picoos_uint8)((val) & 0x00FF); + by[1] = (picoos_uint8)(((val) & 0xFF00)>>8); + return (picoos_WriteBytes(file,by,&len) && (2 == len)); +} +pico_status_t picoos_write_le_uint32 (picoos_File file, picoos_uint32 val) +{ + picoos_int32 len = 4; + picoos_uint8 by[4]; + + by[0] = (picoos_uint8)(val & 0x000000FF); + by[1] = (picoos_uint8)((val & 0x0000FF00)>>8); + by[2] = (picoos_uint8)((val & 0x00FF0000)>>16); + by[3] = (picoos_uint8)((val & 0xFF000000)>>24); + return (picoos_WriteBytes(file,by,&len) && (4 == len)); +} + +/* write pi to mem */ +pico_status_t picoos_write_mem_pi_uint16 (picoos_uint8 * data, picoos_uint32 * pos, picoos_uint16 val) +{ + picoos_uint8 * by = data + *pos; + /* little-endian */ + by[0] = (picoos_uint8)((val) & 0x00FF); + by[1] = (picoos_uint8)(((val) & 0xFF00)>>8); + (*pos) += 2; + return PICO_OK; +} + +/* *****************************************************************/ +/* String search and compare operations */ +/* *****************************************************************/ + +/* this function is case-sensitive */ +picoos_uint8 picoos_has_extension(const picoos_char *str, const picoos_char *suf) +{ + picoos_int32 istr = picoos_strlen(str)-1; + picoos_int32 isuf = picoos_strlen(suf)-1; + while ((istr >= 0) && (isuf >=0) && (str[istr] == suf[isuf])) { + istr--; + isuf--; + } + return (isuf < 0); +} + + +/* *****************************************************************/ +/* String/Number Conversions (may be moved to picopal) */ +/* *****************************************************************/ + +pico_status_t picoos_string_to_int32(picoos_char str[], + picoos_int32 * res) +{ + /* syntax: [+|-] dig {dig} */ + + int i; + int neg; + int val; + int err; + + err = 0; + i = 0; + while ((str[i] <= ' ') && (str[i] != '\0')) { + i++; + } + neg = 0; + if (str[i] == '-') { + neg = 1; + i++; + } else if (str[i] == '+') { + i++; + } + val = 0; + if ((str[i] < '0') || (str[i]> '9')) { + err = 1; + } + while ((str[i] >= '0') && (str[i] <= '9')) { + val = val * 10 + (str[i] - '0'); + i++; + } + while ((str[i] <= ' ') && (str[i] != '\0')) { + i++; + } + if (neg == 1) { + val = -val; + } + if ((err == 0) && (str[i] == '\0')) { + (*res) = val; + return PICO_OK; + } else { + (*res) = 0; + return PICO_EXC_NUMBER_FORMAT; + } +} + +pico_status_t picoos_string_to_uint32(picoos_char str[], + picoos_uint32 * res) +{ + /* syntax: [+] dig {dig} */ + + int i; + int val; + int err; + + err = 0; + i = 0; + while ((str[i] <= ' ') && (str[i] != '\0')) { + i++; + } + if (str[i] == '+') { + i++; + } + val = 0; + if ((str[i] < '0') || (str[i]> '9')) { + err = 1; + } + while ((str[i] >= '0') && (str[i] <= '9')) { + val = val * 10 + (str[i] - '0'); + i++; + } + while ((str[i] <= ' ') && (str[i] != '\0')) { + i++; + } + if ((err == 0) && (str[i] == '\0')) { + (*res) = val; + return PICO_OK; + } else { + (*res) = 0; + return PICO_EXC_NUMBER_FORMAT; + } +} + +/* 'stringlen' is the part of input string to be considered, + * possibly not containing NULLC (e.g. result of strlen). + * 'maxsize' is the maximal size of 'part' including a byte + * for the terminating NULLC! */ +void picoos_get_sep_part_str(picoos_char string[], + picoos_int32 stringlen, picoos_int32 * ind, picoos_char sepCh, + picoos_char part[], picoos_int32 maxsize, picoos_uint8 * done) +{ + + picoos_int32 j; + picoos_uint8 done1; + + if (((*ind) >= stringlen)) { + (*done) = 0; + part[0] = (picoos_char) NULLC; + } else { + done1 = 1; + j = 0; + while ((((*ind) < stringlen) && (string[(*ind)] != sepCh)) && (string[((*ind))] != (picoos_char)NULLC)) { + if ((j < maxsize-1)) { + part[(j)] = string[(*ind)]; + j++; + } else { + done1 = 0; + } + (*ind)++; + } + part[j] = (picoos_char)NULLC; + if ((*ind) < stringlen) { + if (string[(*ind)] == sepCh) { + (*ind)++; /* skip separator character */ + } else if (string[(*ind)] == (picoos_char)NULLC) { + /* reached end of input; set ind to stringlen so that no + more (empty) partial strings will be found */ + (*ind) = stringlen; + } + } + (*done) = done1; + } +} + +/* *****************************************************************/ +/* timer function */ +/* *****************************************************************/ + +extern void picoos_get_timer(picopal_uint32 * sec, picopal_uint32 * usec) +{ + picopal_get_timer(sec, usec); +} + +#ifdef __cplusplus +} +#endif + + +/* end */ diff --git a/pico/lib/picoos.h b/pico/lib/picoos.h new file mode 100644 index 0000000..859e176 --- /dev/null +++ b/pico/lib/picoos.h @@ -0,0 +1,550 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picoos.h + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ +/** + * @addtogroup picoos + + * Operating system generalization module \n + * +*/ + +#ifndef PICOOS_H_ +#define PICOOS_H_ + +#include "picodefs.h" +#include "picopal.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* some "switch" used in picopal and in picocep ... */ +#define PICOOS_DIV_USE_INV PICOPAL_DIV_USE_INV + +/* *************************************************/ +/* types */ +/* *************************************************/ + +typedef picopal_uint8 picoos_uint8; +typedef picopal_uint16 picoos_uint16; +typedef picopal_uint32 picoos_uint32; + +typedef picopal_int8 picoos_int8; +typedef picopal_int16 picoos_int16; +typedef picopal_int32 picoos_int32; + +typedef picopal_double picoos_double; +typedef picopal_single picoos_single; + +typedef picopal_char picoos_char; +typedef picopal_uchar picoos_uchar; + +typedef picopal_uint8 picoos_bool; + +typedef picopal_objsize_t picoos_objsize_t; +typedef picopal_ptrdiff_t picoos_ptrdiff_t; + +/* *************************************************/ +/* functions */ +/* *************************************************/ + + +picoos_int32 picoos_atoi(const picoos_char *); +picoos_int8 picoos_strcmp(const picoos_char *, const picoos_char *); +picoos_int8 picoos_strncmp(const picoos_char *a, const picoos_char *b, picoos_objsize_t siz); +picoos_uint32 picoos_strlen(const picoos_char *); +picoos_char * picoos_strchr(const picoos_char *, picoos_char); +picoos_char *picoos_strstr(const picoos_char *s, const picoos_char *substr); +picoos_int16 picoos_slprintf(picoos_char * b, picoos_uint32 bsize, const picoos_char *f, ...); +picoos_char * picoos_strcpy(picoos_char *, const picoos_char *); +picoos_char * picoos_strcat(picoos_char *, const picoos_char *); + +/* copies 'length' bytes from 'src' to 'dest'. (regions may be overlapping) no error checks! */ +void * picoos_mem_copy(const void * src, void * dst, picoos_objsize_t length); + +/* safe versions */ +picoos_objsize_t picoos_strlcpy(picoos_char *dst, const picoos_char *src, picoos_objsize_t siz); +void * picoos_mem_set(void * dest, picoos_uint8 byte_val, picoos_objsize_t length); + +picoos_double picoos_cos(const picoos_double cos_arg); +picoos_double picoos_sin(const picoos_double sin_arg); +picoos_double picoos_fabs(const picoos_double fabs_arg); + +picoos_double picoos_quick_exp(const picoos_double y); + + +void picoos_get_sep_part_str (picoos_char string[], picoos_int32 stringlen, picoos_int32 * ind, picoos_char sepCh, picoos_char part[], picoos_int32 maxsize, picoos_uint8 * done); +pico_status_t picoos_string_to_uint32 (picoos_char str[], picoos_uint32 * res); +pico_status_t picoos_string_to_int32 (picoos_char str[], picoos_int32 * res); + +/* *****************************************************************/ +/* "Common" */ +/* *****************************************************************/ +/* picoos_common is a collection of basic functionalities that must be globally accesible from every "big" function. + * It includes pointers to the MemoryManasger, ExceptionManager and a list of open files. */ + +typedef struct memory_manager * picoos_MemoryManager; +typedef struct picoos_exception_manager * picoos_ExceptionManager; +typedef struct picoos_file * picoos_File; + + +/** object : Common + * shortcut : common + * + */ +typedef struct picoos_common * picoos_Common; + +/* the picoos_common structure itself is exported so no access functions are needed. Handle with care! (might be changed later) */ +typedef struct picoos_common { + picoos_ExceptionManager em; + picoos_MemoryManager mm; + picoos_File fileList; +} picoos_common_t; + +picoos_Common picoos_newCommon(picoos_MemoryManager mm); + +void picoos_disposeCommon(picoos_MemoryManager mm, picoos_Common * this); + + +/* *****************************************************************/ +/* Memory Management */ +/* *****************************************************************/ + +typedef picoos_char * byte_ptr_t; + +#define PICOOS_ALIGN_SIZE 8 + + + +void * picoos_raw_malloc(byte_ptr_t raw_mem, + picoos_objsize_t raw_mem_size, picoos_objsize_t alloc_size, + byte_ptr_t * rest_mem, picoos_objsize_t * rest_mem_size); + +/** + * Creates a new memory manager object for the specified raw memory + * block. 'enableProtMem' enables or disables memory protection + * functionality; if disabled, picoos_protectMem() has no effect. + */ +picoos_MemoryManager picoos_newMemoryManager( + void *raw_memory, + picoos_objsize_t size, + picoos_bool enableMemProt); + + + +void picoos_disposeMemoryManager(picoos_MemoryManager * mm); + + +void * picoos_allocate(picoos_MemoryManager this, picoos_objsize_t byteSize); +void picoos_deallocate(picoos_MemoryManager this, void * * adr); + +/* the following memory manager routines are for testing and + debugging purposes */ + +/** + * Same as picoos_allocate, but write access to the memory block may be + * prohibited by a subsequent call to picoos_protectMem(). + */ +void *picoos_allocProtMem(picoos_MemoryManager mm, picoos_objsize_t byteSize); + +/** + * Releases a memory block previously allocated by picoos_allocProtMem(). + */ +void picoos_deallocProtMem(picoos_MemoryManager mm, void **addr); + +/** + * Enables or disables write protection of a memory block previously + * allocated by picoos_allocProtMem(). If write protection is enabled, + * any subsequent write access will cause a segmentation fault. + */ +void picoos_protectMem( + picoos_MemoryManager mm, + void *addr, + picoos_objsize_t len, + picoos_bool enable); + +void picoos_getMemUsage( + picoos_MemoryManager this, + picoos_bool resetIncremental, + picoos_int32 *usedBytes, + picoos_int32 *incrUsedBytes, + picoos_int32 *maxUsedBytes); + +void picoos_showMemUsage( + picoos_MemoryManager this, + picoos_bool incremental, + picoos_bool resetIncremental); + +/* *****************************************************************/ +/* Exception Management */ +/* *****************************************************************/ +/** object : ExceptionManager + * shortcut : em + * + */ + + +#define PICOOS_MAX_EXC_MSG_LEN 512 +#define PICOOS_MAX_WARN_MSG_LEN 64 +#define PICOOS_MAX_NUM_WARNINGS 8 + +void picoos_setErrorMsg(picoos_char * dst, picoos_objsize_t siz, + picoos_int16 code, picoos_char * base, const picoos_char *fmt, ...); + + +picoos_ExceptionManager picoos_newExceptionManager(picoos_MemoryManager mm); + +void picoos_disposeExceptionManager(picoos_MemoryManager mm, + picoos_ExceptionManager * this); + + +void picoos_emReset(picoos_ExceptionManager this); + +/* For convenience, this function returns the resulting exception code of 'this' + * (as would be returned by emGetExceptionCode). + * The return value therefore is NOT the status of raising + * the error! */ +pico_status_t picoos_emRaiseException(picoos_ExceptionManager this, + pico_status_t exceptionCode, picoos_char * baseMessage, picoos_char * fmt, ...); + +pico_status_t picoos_emGetExceptionCode(picoos_ExceptionManager this); + +void picoos_emGetExceptionMessage(picoos_ExceptionManager this, picoos_char * msg, picoos_uint16 maxsize); + +void picoos_emRaiseWarning(picoos_ExceptionManager this, + pico_status_t warningCode, picoos_char * baseMessage, picoos_char * fmt, ...); + +picoos_uint8 picoos_emGetNumOfWarnings(picoos_ExceptionManager this); + +pico_status_t picoos_emGetWarningCode(picoos_ExceptionManager this, picoos_uint8 warnNum); + +void picoos_emGetWarningMessage(picoos_ExceptionManager this, picoos_uint8 warnNum, picoos_char * msg, picoos_uint16 maxsize); + + + + +/* *****************************************************************/ +/* File Access */ +/* *****************************************************************/ + +#define picoos_MaxFileNameLen 512 +#define picoos_MaxKeyLen 512 +#define picoos_MaxPathLen 512 +#define picoos_MaxPathListLen 2048 + +typedef picoos_char picoos_Key[picoos_MaxKeyLen]; +typedef picoos_char picoos_FileName[picoos_MaxFileNameLen]; +typedef picoos_char picoos_Path[picoos_MaxPathLen]; +typedef picoos_char picoos_PathList[picoos_MaxPathListLen]; + + +/* ***** Sequential binary file access ******/ + +/* Remark: 'ReadByte', 'ReadBytes' and 'ReadVar' may be mixed; + 'WriteByte', 'WriteBytes' and 'WriteVar' may be mixed. */ + +/* Open existing binary file for read access. */ +picoos_uint8 picoos_OpenBinary(picoos_Common g, picoos_File * f, picoos_char name[]); + + +/* Read next byte from file 'f'. */ +picoos_uint8 picoos_ReadByte(picoos_File f, picoos_uint8 * by); + +/* Read next 'len' bytes from 'f' into 'bytes'; 'len' returns the + number of bytes actually read (may be smaller than requested + length if 'bytes' is too small to hold all bytes or at end of file). + Remark: 'bytes' is compabtible with any variable of any size. */ +picoos_uint8 picoos_ReadBytes(picoos_File f, picoos_uint8 bytes[], + picoos_uint32 * len); + + +/* Create new binary file. + If 'key' is not empty, the file is encrypted with 'key'. */ +picoos_uint8 picoos_CreateBinary(picoos_Common g, picoos_File * f, picoos_char name[]); + +picoos_uint8 picoos_WriteByte(picoos_File f, picoos_char by); + +/* Writes 'len' bytes from 'bytes' onto file 'f'; 'len' returns + the number of bytes actually written. */ +picoos_uint8 picoos_WriteBytes(picoos_File f, const picoos_char bytes[], + picoos_int32 * len); + + +/* Close previously opened binary file. */ +picoos_uint8 picoos_CloseBinary(picoos_Common g, picoos_File * f); + + + + + + +pico_status_t picoos_read_le_int16 (picoos_File file, picoos_int16 * val); +pico_status_t picoos_read_le_uint16 (picoos_File file, picoos_uint16 * val); +pico_status_t picoos_read_le_uint32 (picoos_File file, picoos_uint32 * val); + + +pico_status_t picoos_read_pi_uint16 (picoos_File file, picoos_uint16 * val); +pico_status_t picoos_read_pi_uint32 (picoos_File file, picoos_uint32 * val); + +pico_status_t picoos_write_le_uint16 (picoos_File file, picoos_uint16 val); +pico_status_t picoos_write_le_uint32 (picoos_File file, picoos_uint32 val); + +/* +pico_status_t picoos_write_pi_uint32 (picoos_File file, const picoos_uint32 val); + +pico_status_t picoos_write_pi_uint16 (picoos_File file, const picoos_uint16 val); +*/ + + +/* **************************************************************************************/ +/* *** general file routines *****/ + +/* Returns whether end of file was encountered in previous + read operation. */ +picoos_bool picoos_Eof(picoos_File f); + +/* sets the file pointer to + 'pos' bytes from beginning (first byte = byte 0). This + routine should only be used for binary files. */ +picoos_bool picoos_SetPos(picoos_File f, picoos_int32 pos); + +/* Get position from file 'f'. */ +picoos_bool picoos_GetPos(picoos_File f, picoos_uint32 * pos); + +/* Returns the length of the file in bytes. */ +picoos_bool picoos_FileLength(picoos_File f, picoos_uint32 * len); + +/* Return full name of file 'f'. */ +picoos_bool picoos_Name(picoos_File f, picoos_char name[], picoos_uint32 maxsize); + +/* Returns whether file 'name' exists or not. */ +picoos_bool picoos_FileExists(picoos_Common g, picoos_char name[] /*, picoos_char ckey[] */); + +/* Delete a file. */ +picoos_bool picoos_Delete(picoos_char name[]); + +/* Rename a file. */ +picoos_bool picoos_Rename(picoos_char oldName[], picoos_char newName[]); + + +/* *****************************************************************/ +/* Sampled Data Files */ +/* *****************************************************************/ + +#define SAMPLE_FREQ_16KHZ (picoos_uint32) 16000 + +typedef enum { + FILE_TYPE_WAV, + FILE_TYPE_AU, + FILE_TYPE_RAW, + FILE_TYPE_OTHER +} wave_file_type_t; + +typedef enum { + FORMAT_TAG_LIN = 1, /**< linear 16-bit encoding */ + FORMAT_TAG_ALAW = 6, /**< a-law encoding, 8 bit */ + FORMAT_TAG_ULAW = 7 /**< u-law encoding, 8 bit */ + /* there are many more */ +} wave_format_tag_t; + + +typedef enum { + /* values corresponding RIFF wFormatTag */ + PICOOS_ENC_LIN = FORMAT_TAG_LIN, /**< linear 16-bit encoding; standard */ + PICOOS_ENC_ALAW = FORMAT_TAG_ALAW, /**< a-law encoding, 8 bit */ + PICOOS_ENC_ULAW = FORMAT_TAG_ULAW, /**< u-law encoding, 8 bit */ + /* values outside RIFF wFormatTag values (above 4100) */ + PICOOS_ENC_OTHER = 5000 /**< other; (treated as raw) */ + } picoos_encoding_t; + +typedef struct picoos_sd_file * picoos_SDFile; + +/* SDFile input functions */ + +/* orig. comment from SDInOut.def + Opens sampled data file 'fileName' for input and returns + the encoding 'enc' of the file, sampling rate 'sf', + nr of samples 'nrSamples', and a handle to the opened file + in 'sdFile'. + + If 'fileName' is empty, the input is taken from the direct + acoustic input using the sampling rate specified by + "SetRawDefaults". In this case, 'encoding' returns 'EncLin', + and 'nrSamples' returns 0. + + The file format is taken from the file name extension: + ".wav" --> wav file + ".au" --> au file + other extensions --> headerless files + + For wav and au files, the sampling rate and encoding are taken + from the file header and returned in 'sf' and 'enc'. For + headerless files, 'sf' and 'enc' are taken from the + most recently set default values (procedure SetRawDefaults). + + 'done' returns whether the sampled data file was successfully + opened. */ +extern picoos_bool picoos_sdfOpenIn (picoos_Common g, picoos_SDFile * sdFile, picoos_char fileName[], picoos_uint32 * sf, picoos_encoding_t * enc, picoos_uint32 * nrSamples); + + +extern picoos_bool picoos_sdfGetSamples (picoos_SDFile sdFile, picoos_uint32 start, picoos_uint32 * nrSamples, picoos_int16 samples[]); + + +extern picoos_bool picoos_sdfCloseIn (picoos_Common g, picoos_SDFile * sdFile); + + +/* SDFile output functions*/ + +extern picoos_bool picoos_sdfOpenOut (picoos_Common g, picoos_SDFile * sdFile, picoos_char fileName[], int sf, picoos_encoding_t enc); + + +extern picoos_bool picoos_sdfPutSamples (picoos_SDFile sdFile, picoos_uint32 nrSamples, picoos_int16 samples[]); + +/* +extern picoos_bool picoos_AbortOutput (picoos_SDFile sdFile); + + +extern picoos_bool picoos_ResumeOutput (picoos_SDFile sdFile); + + +extern picoos_bool picoos_FlushOutput (picoos_SDFile sdFile); +*/ + +extern picoos_bool picoos_sdfCloseOut (picoos_Common g, picoos_SDFile * sdFile); + + +/* *****************************************************************/ +/* File Headers */ +/* *****************************************************************/ + +#define PICOOS_MAX_FIELD_STRING_LEN 32 /* including terminating char */ + +#define PICOOS_MAX_NUM_HEADER_FIELDS 10 +#define PICOOS_NUM_BASIC_HEADER_FIELDS 5 + +#define PICOOS_HEADER_NAME 0 +#define PICOOS_HEADER_VERSION 1 +#define PICOOS_HEADER_DATE 2 +#define PICOOS_HEADER_TIME 3 +#define PICOOS_HEADER_CONTENT_TYPE 4 + +#define PICOOS_MAX_HEADER_STRING_LEN (PICOOS_MAX_NUM_HEADER_FIELDS * (2 * PICOOS_MAX_FIELD_STRING_LEN)) + +typedef picoos_char picoos_field_string_t[PICOOS_MAX_FIELD_STRING_LEN]; + +typedef picoos_char picoos_header_string_t[PICOOS_MAX_HEADER_STRING_LEN]; + +typedef enum {PICOOS_FIELD_IGNORE, PICOOS_FIELD_EQUAL, PICOOS_FIELD_COMPAT} picoos_compare_op_t; + +/* private */ +typedef struct picoos_file_header_field { + picoos_field_string_t key; + picoos_field_string_t value; + picoos_compare_op_t op; +} picoos_file_header_field_t; + +/* public */ +typedef struct picoos_file_header * picoos_FileHeader; +typedef struct picoos_file_header { + picoos_uint8 numFields; + picoos_file_header_field_t field[PICOOS_MAX_NUM_HEADER_FIELDS]; +} picoos_file_header_t; + + +pico_status_t picoos_clearHeader(picoos_FileHeader header); + +pico_status_t picoos_setHeaderField(picoos_FileHeader header, picoos_uint8 index, picoos_char * key, picoos_char * value, picoos_compare_op_t op); + +/* caller has to make sure allocated space at key and value are large enough to hold a picoos_field_string */ +pico_status_t picoos_getHeaderField(picoos_FileHeader header, picoos_uint8 index, picoos_field_string_t key, picoos_field_string_t value, picoos_compare_op_t * op); + +/* caller has to make sure allocated space at str is large enough to hold the header in question */ +/* +pico_status_t picoos_hdrToString(picoos_FileHeader header, picoos_header_string_t str); +*/ + +pico_status_t picoos_hdrParseHeader(picoos_FileHeader header, picoos_header_string_t str); + +pico_status_t picoos_getSVOXHeaderString(picoos_char * str, picoos_uint8 * len, picoos_uint32 maxlen); + +pico_status_t picoos_readPicoHeader(picoos_File f, picoos_uint32 * headerlen); + + + +/* *****************************************************************/ +/* String search and compare operations */ +/* *****************************************************************/ + + +picoos_uint8 picoos_has_extension(const picoos_char *str, const picoos_char *suf); + +/* *****************************************************************/ +/* String/Number Manipulations (might be moved to picopal) */ +/* *****************************************************************/ + +pico_status_t picoos_string_to_int32(picoos_char str[], + picoos_int32 * res); + +pico_status_t picoos_string_to_uint32(picoos_char str[], + picoos_uint32 * res); + +/* 'stringlen' is the part of input string to be considered, possibly not containing NULLC (e.g. result of strlen). + * 'maxsize' is the maximal size of 'part' including a byte for the terminating NULLC! */ +void picoos_get_sep_part_str(picoos_char string[], + picoos_int32 stringlen, picoos_int32 * ind, picoos_char sepCh, + picoos_char part[], picoos_int32 maxsize, picoos_uint8 * done); + +/* searches for the first contiguous string of printable characters (> ' ') inside fromStr, possibly skipping + * chars <= ' ') and returns it in toStr. + * fromStr is assumed to be NULLC terminated and toStr is forced to be NULLC terminated within maxsize. + * The search is started at *pos inside fromStr and at return, *pos is the position within fromStr after the + * found string, or the position after the end of fromStr, if no string was found. + * the function returns TRUE if a string was found and fitted toStr, or FALSE otherwise. */ +picoos_uint8 picoos_get_str (picoos_char * fromStr, picoos_uint32 * pos, picoos_char * toStr, picoos_objsize_t maxsize); + + +pico_status_t picoos_read_mem_pi_uint16 (picoos_uint8 * data, picoos_uint32 * pos, picoos_uint16 * val); + +pico_status_t picoos_read_mem_pi_uint32 (picoos_uint8 * data, picoos_uint32 * pos, picoos_uint32 * val); + +pico_status_t picoos_write_mem_pi_uint16 (picoos_uint8 * data, picoos_uint32 * pos, picoos_uint16 val); + + +/* *****************************************************************/ +/* timer function */ +/* *****************************************************************/ + +void picoos_get_timer(picopal_uint32 * sec, picopal_uint32 * usec); + +#ifdef __cplusplus +} +#endif + + +#endif /*PICOOS_H_*/ diff --git a/pico/lib/picopal.c b/pico/lib/picopal.c new file mode 100644 index 0000000..db05e2b --- /dev/null +++ b/pico/lib/picopal.c @@ -0,0 +1,554 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picopal.c + * + * pico platform abstraction layer + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +/* GCC does not supporte #pragma message */ +#if !defined(__GNUC__) +#define PRAGMA_MESSAGE +#endif + +#if defined(PRAGMA_MESSAGE) && defined(PICO_PLATFORM) +#pragma message("PICO_PLATFORM : is defined externally") +#endif + +#if defined(PRAGMA_MESSAGE) && defined(_WIN32) +#pragma message("_WIN32 : is defined") +#endif + +#if defined(PRAGMA_MESSAGE) && defined(__APPLE__) +#pragma message("__APPLE__ : is defined") +#endif + +#if defined(PRAGMA_MESSAGE) && defined(__MACH__) +#pragma message("__MACH__ : is defined") +#endif + +#if defined(PRAGMA_MESSAGE) && defined(macintosh) +#pragma message("macintosh : is defined") +#endif + +#if defined(PRAGMA_MESSAGE) && defined(linux) +#pragma message("linux : is defined") +#endif +#if defined(PRAGMA_MESSAGE) && defined(__linux__) +#pragma message("__linux__ : is defined") +#endif +#if defined(PRAGMA_MESSAGE) && defined(__linux) +#pragma message("__linux : is defined") +#endif + + +#include +#include +#include +#include + +#include "picodefs.h" +#include "picopal.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +#if PICO_PLATFORM == PICO_Windows +/* use high-resolution timer functions on Windows platform */ +#define USE_CLOCK 0 +#else +/* use clock() function instead of high-resolution timer on + non-Windows platforms */ +#define USE_CLOCK 1 +#endif + +#include +#if PICO_PLATFORM == PICO_Windows +#include +#endif + +#if defined(PRAGMA_MESSAGE) +#pragma message("PICO_PLATFORM : " PICO_PLATFORM_STRING) +#endif + + +picopal_int32 picopal_atoi(const picopal_char *s) { + return (picopal_int32)atoi((const char *)s); +} + +picopal_int32 picopal_strcmp(const picopal_char *a, const picopal_char *b) { + return (picopal_int32)strcmp((const char *)a, (const char *)b); +} + +picopal_int32 picopal_strncmp(const picopal_char *a, const picopal_char *b, picopal_objsize_t siz) { + return (picopal_int32)strncmp((const char *)a, (const char *)b, (size_t) siz); +} + +picopal_objsize_t picopal_strlen(const picopal_char *s) { + return (picopal_objsize_t)strlen((const char *)s); +} + +picopal_char *picopal_strchr(const picopal_char *s, picopal_char c) { + return (picopal_char *)strchr((const char *)s, (int)c); +} + +picopal_char *picopal_strstr(const picopal_char *s, const picopal_char *substr) { + return (picopal_char *)strstr((const char *)s, (const char *)substr); +} + +picopal_char *picopal_strcpy(picopal_char *d, const picopal_char *s) { + return (picopal_char *)strcpy((char *)d, (const char *)s); +} + +picopal_char *picopal_strcat(picopal_char *dest, const picopal_char *src) { + return (picopal_char *)strcat((char *)dest, (const char *)src); +} + + +/* copy src into dst, but make sure that dst is not accessed beyond its size 'siz' and is allways NULLC-terminated. + * 'siz' is the number of bytes of the destination, including one byte for NULLC! + * returns the full length of the input string, not including termination NULLC (strlen(src)). + * the copy is successfull without truncation if picopal_strlcpy(dst,src,siz) < siz */ +picopal_objsize_t picopal_strlcpy(picopal_char *dst, const picopal_char *src, picopal_objsize_t siz) +{ + picopal_char *d = dst; + const picopal_char *s = src; + picopal_objsize_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0) { + while (--n != 0) { + if ((*(d++) = *(s++)) == NULLC) { + break; + } + } + } + + /* Not enough room in dst, add NULLC and traverse rest of src */ + if (n == 0) { + if (siz != 0) { + *d = NULLC; /* NULLC-terminate dst */ + } + while (*(s++)) {} + ; + } + + return(s - src - 1); /* count does not include NULLC */ +} + + +picopal_int16 picopal_sprintf(picopal_char * dst, const picopal_char *fmt, ...) +{ + picopal_int16 i; + va_list args; + + va_start(args, (char *)fmt); + i = (picopal_int16)vsprintf((char *) dst, (const char *)fmt, args); + va_end(args); + return i; +} + + +picopal_objsize_t picopal_vslprintf(picopal_char * dst, picopal_objsize_t siz, const picopal_char *fmt, va_list args) { + picopal_char buf[21]; + picopal_char *d = dst; + const picopal_char *f = fmt; + picopal_char * b; + picopal_objsize_t len, nnew, n = siz; + picopal_int32 ival; + picopal_char cval; + picopal_objsize_t i = 0; + + if (!f) { + f = (picopal_char *) ""; + } + while (*f) { + if (*f == '%') { + switch (*(++f)) { + case 'i': + f++; + ival = va_arg(args,int); + picopal_sprintf(buf,(picopal_char *)"%i",ival); + b = buf; + break; + case 'c': + f++; + cval = va_arg(args,int); + picopal_sprintf(buf,(picopal_char *)"%c",cval); + b = buf; + break; + case 's': + f++; + b = (picopal_char *) va_arg(args, char*); + break; + default: + if (n > 0) { + (*d++) = '%'; + n--; + } + i++; + b = NULL; + break; + } + if (b) { + len = picopal_strlcpy(d,b,n); /* n1 is the actual length of sval */ + i += len; + nnew = (n > len) ? n-len : 0; /* nnew is the new value of n */ + d += (n - nnew); + n = nnew; + } + } else { + if (n) { + (*d++) = (*f); + n--; + } + i++; + f++; + } + } + + return i; +} + +picopal_objsize_t picopal_slprintf(picopal_char * dst, picopal_objsize_t siz, const picopal_char *fmt, /*args*/ ...) { + picopal_objsize_t i; + va_list args; + + va_start(args, (char *)fmt); + i = picopal_vslprintf(dst, siz, fmt, args); + va_end(args); + return i; + +} + + +/* copies 'length' bytes from 'src' to 'dest'. (regions may be overlapping) no error checks! */ +void * picopal_mem_copy(const void * src, void * dst, picopal_objsize_t length) +{ + return memmove(dst, src, (size_t) length); +} + +/* sets 'length' bytes starting at dest[0] to 'byte_val' */ +void * picopal_mem_set(void * dest, picopal_uint8 byte_val, picopal_objsize_t length) +{ + return memset(dest, (int) byte_val, (size_t) length); +} + +/* *************************************************/ +/* fixed-point math */ +/* *************************************************/ + +/* *************************************************/ +/* transcendent math */ +/* *************************************************/ + + +picopal_double picopal_cos(const picopal_double cos_arg) +{ + return (picopal_double) cos((double)cos_arg); +} +picopal_double picopal_sin(const picopal_double sin_arg) +{ + return (picopal_double) sin((double) sin_arg); +} +picopal_double picopal_fabs(const picopal_double fabs_arg) +{ + return (picopal_double) fabs((double) fabs_arg); +} + + +/* *************************************************/ +/* file access */ +/* *************************************************/ +#define PICOPAL_EOL '\n' + +picopal_char picopal_eol(void) +{ + return PICOPAL_EOL; +} + +/* 'fopen' opens the file with name 'filename'. Depending on + 'mode' : + 'PICOPAL_TEXT_READ' : Opens an existing text file for reading. + The file is positioned at the beginning of the file. + 'PICOPAL_TEXT_WRITE' : Opens and truncates an existing file or creates a new + text file for writing. The file is positioned at the + beginning. + 'PICOPAL_BIN_READ' : Opens an existing binary file for reading. + The file is positioned at the beginning of the file. + 'PICOPAL_BIN_WRITE' : Opens and truncates an existing file or creates a new + binary file for writing. The file is positioned at the + beginning. + If the opening of the file is successful a file pointer is given + back. Otherwise a NIL-File is given back. +*/ +picopal_File picopal_fopen (picopal_char filename[], picopal_access_mode mode) +{ + picopal_File res; + + switch (mode) { + case PICOPAL_TEXT_READ : + res = (picopal_File) fopen((char *)filename, (char *)"r"); + break; + case PICOPAL_TEXT_WRITE : + res = (picopal_File) fopen((char *)filename, (char *)"w"); + break; + case PICOPAL_BINARY_READ : + res = (picopal_File) fopen((char *)filename, (char *)"rb"); + break; + case PICOPAL_BINARY_WRITE : + res = (picopal_File) fopen((char *)filename, (char *)"wb"); + break; + default : + res = (picopal_File) NULL; + } + return res; + +} + + +picopal_File picopal_get_fnil (void) +{ + return (picopal_File) NULL; +} + + +picopal_int8 picopal_is_fnil (picopal_File f) +{ + return (NULL == f); +} + +pico_status_t picopal_fflush (picopal_File f) +{ + return (0 == fflush((FILE *)f)) ? PICO_OK : PICO_EOF; +} + + +pico_status_t picopal_fclose (picopal_File f) +{ + return (0 == fclose((FILE *)f)) ? PICO_OK : PICO_EOF; +} + + + +picopal_uint32 picopal_flength (picopal_File stream) +{ + fpos_t fpos; + picopal_int32 len; + + fgetpos((FILE *)stream,&fpos); + picopal_fseek(stream,0,SEEK_END); + len = ftell((FILE *)stream); + fsetpos((FILE *)stream,&fpos); + clearerr((FILE *)stream); + return len; + +} + +picopal_uint8 picopal_feof (picopal_File stream) +{ + return (0 != feof((FILE *)stream)); + +} + +pico_status_t picopal_fseek (picopal_File f, picopal_uint32 offset, picopal_int8 seekmode) +{ + return (0 == fseek((FILE *)f, offset, seekmode)) ? PICO_OK : PICO_EOF; +} + +pico_status_t picopal_fget_char (picopal_File f, picopal_char * ch) +{ + picopal_int16 res; + + res = fgetc((FILE *)f); + if (res >= 0) { + *ch = (picopal_char) res; + } + else { + *ch = '\0'; + } + return (res >= 0) ? PICO_OK : PICO_EOF; +} + +picopal_objsize_t picopal_fread_bytes (picopal_File f, void * ptr, picopal_objsize_t objsize, picopal_uint32 nobj) +{ + return (picopal_objsize_t) fread(ptr, objsize, nobj, (FILE *)f); +} + +picopal_objsize_t picopal_fwrite_bytes (picopal_File f, void * ptr, picopal_objsize_t objsize, picopal_uint32 nobj){ return (picopal_objsize_t) fwrite(ptr, objsize, nobj, (FILE *)f);} +/* *************************************************/ +/* functions for debugging/testing purposes only */ +/* *************************************************/ + +void *picopal_mpr_alloc(picopal_objsize_t size) +{ +#if PICO_PLATFORM == PICO_Windows + return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); +#else + /* not yet implemented for other platforms; corresponding + function on UNIX systems is pvalloc */ + return NULL; +#endif + size = size; /* avoid warning "var not used in this function"*/ + +} + +void picopal_mpr_free(void **p) +{ +#if PICO_PLATFORM == PICO_Windows + VirtualFree(*p, 0, MEM_RELEASE); +#else + /* not yet implemented for other platforms */ +#endif + *p = NULL; +} + +pico_status_t picopal_mpr_protect(void *addr, picopal_objsize_t len, picopal_int16 prot) +{ + pico_status_t status = PICO_OK; + +#if PICO_PLATFORM == PICO_Windows + DWORD dwNewProtect, dwOldProtect; + dwNewProtect = PICOPAL_PROT_NONE; + if (prot & PICOPAL_PROT_READ) { + if (prot & PICOPAL_PROT_WRITE) { + dwNewProtect = PAGE_READWRITE; + } else { + dwNewProtect = PAGE_READONLY; + } + } else if (prot & PICOPAL_PROT_WRITE) { + /* under Windows write-only is not possible */ + dwNewProtect = PAGE_READWRITE; + } + if (!VirtualProtect(addr, len, dwNewProtect, &dwOldProtect)) { + status = PICO_ERR_OTHER; + } +#else + /* not yet implemented for other platforms */ + addr = addr; /* avoid warning "var not used in this function"*/ + len = len; /* avoid warning "var not used in this function"*/ + prot = prot; /* avoid warning "var not used in this function"*/ + +#endif + return status; +} +/* + * Reference: + * A Fast, Compact Approximation of the Exponential Function by Nicol N. Schraudolph in Neural Computation, 11,853-862 (1999) + * See also: http://www-h.eng.cam.ac.uk/help/tpl/programs/Matlab/mex.html + * + */ +picopal_double picopal_quick_exp(const picopal_double y) { + union { + picopal_double d; + struct { + #if PICO_ENDIANNESS == ENDIANNESS_LITTLE /* little endian */ + picopal_int32 j,i; + #else + picopal_int32 i,j; + #endif + } n; + + } _eco; + _eco.n.i = (picopal_int32)(1512775.3951951856938297995605697f * y) + 1072632447; + return _eco.d; +} + + +/* *************************************************/ +/* timer */ +/* *************************************************/ + +#if IMPLEMENT_TIMER + +#define USEC_PER_SEC 1000000 + +typedef clock_t picopal_clock_t; + + +#if USE_CLOCK +picopal_clock_t startTime; +#else +int timerInit = 0; +LARGE_INTEGER startTime; +LARGE_INTEGER timerFreq; +#endif + + +picopal_clock_t picopal_clock(void) +{ + return (picopal_clock_t)clock(); +} + +#endif /* IMPLEMENT_TIMER */ + +void picopal_get_timer(picopal_uint32 * sec, picopal_uint32 * usec) +{ +#if IMPLEMENT_TIMER +#if USE_CLOCK + picopal_clock_t dt; + dt = picopal_clock() - startTime; + *sec = dt / CLOCKS_PER_SEC; + *usec = USEC_PER_SEC * (dt % CLOCKS_PER_SEC) / CLOCKS_PER_SEC; +#else + LARGE_INTEGER now; + if (!timerInit) { + QueryPerformanceFrequency(&timerFreq); + timerInit = 1; + } + if (QueryPerformanceCounter(&now) && 0) { +/* + LONGLONG dt, tf; + dt = now.QuadPart - GLOB(startTime).QuadPart; + tf = GLOB(timerFreq).QuadPart; + *sec = (unsigned int) (dt / tf); + *usec = (unsigned int) (USEC_PER_SEC * (dt % tf) / tf); +*/ + double dt, tf; + dt = (double)(now.QuadPart - startTime.QuadPart); + tf = (double)(timerFreq.QuadPart); + *sec = (unsigned int) (dt /tf); + *usec = (unsigned int) ((double)USEC_PER_SEC * (dt / tf)) % USEC_PER_SEC; + } else { + /* high freq counter not supported by system */ + DWORD dt; + dt = GetTickCount() - startTime.LowPart; + *sec = dt / 1000; + *usec = 1000 * (dt % 1000); + } +#endif /* USE_CLOCK */ +#else + *sec = 0; + *usec = 0; +#endif /* IMPLEMENT_TIMER */ +} + +#ifdef __cplusplus +} +#endif + +/* End picopal.c */ diff --git a/pico/lib/picopal.h b/pico/lib/picopal.h new file mode 100644 index 0000000..f0c0439 --- /dev/null +++ b/pico/lib/picopal.h @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picopal.h + * + * pico plattform abstraction layer + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ +/** + * @addtogroup picoos + + * Operating system Platform Specific implementation module \n + * +*/ +#ifndef PICOPAL_H_ +#define PICOPAL_H_ + +#include +#include +#include +#include +#include +#include +#include "picopltf.h" +#include "picodefs.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* *********************************************************/ +/* general defines and typedefs (used to be in picodefs.h) */ +/* *********************************************************/ + +#define TRUE 1 +#define FALSE 0 + +#ifndef NULL +#define NULL 0 +#endif + +#define NULLC '\000' + + +/* "strange" defines to switch variants... */ +#define PICOPAL_DIV_USE_INV 0 + + +/*---------------Externals-----------------------*/ +/* used by picocep*/ +#if defined(PICO_DEBUG) + extern int numlongmult, numshortmult; +#endif + + +typedef signed int pico_status_t; + + +/* unfortunately, ANSI-C uses eof for results and exceptional results .. */ +/* in the context of reading from a CharBuffer, eof means "no more + input available FOR NOW" */ + +#define PICO_EOF (pico_status_t) -1 + + +/* *************************************************/ +/* constants */ +/* *************************************************/ + + + /* operating system identifications */ +#define PICOPAL_OS_NIL 0 /* just an unchangeable first value */ +#define PICOPAL_OS_WINDOWS 1 +/* ... */ +#define PICOPAL_OS_GENERIC 99 /* must always be the last value */ + +/* *************************************************/ +/* types */ +/* *************************************************/ + +typedef unsigned char picopal_uint8; +typedef unsigned short picopal_uint16; +typedef unsigned int picopal_uint32; + +typedef signed char picopal_int8; +typedef signed short picopal_int16; +typedef signed int picopal_int32; + +typedef float picopal_single; +typedef double picopal_double; + +typedef unsigned char picopal_char; + +typedef unsigned char picopal_uchar; + +typedef size_t picopal_objsize_t; +typedef ptrdiff_t picopal_ptrdiff_t; + +/* *************************************************/ +/* functions */ +/* *************************************************/ + +picopal_int32 picopal_atoi(const picopal_char *); + +picopal_int32 picopal_strcmp(const picopal_char *, const picopal_char *); +picopal_int32 picopal_strncmp(const picopal_char *a, const picopal_char *b, picopal_objsize_t siz); +picopal_objsize_t picopal_strlen(const picopal_char *); +picopal_char * picopal_strchr(const picopal_char *, picopal_char); +picopal_char * picopal_strcpy(picopal_char *d, const picopal_char *s); +picopal_char *picopal_strstr(const picopal_char *s, const picopal_char *substr); +picopal_char *picopal_strcat(picopal_char *dest, const picopal_char *src); +picopal_int16 picopal_sprintf(picopal_char * dst, const picopal_char *fmt, ...); + +/* copies 'length' bytes from 'src' to 'dest'. (regions may be overlapping) no error checks! */ +void * picopal_mem_copy(const void * src, void * dst, picopal_objsize_t length); + +/* sets 'length' bytes starting at dest[0] to 'byte_val' */ +void * picopal_mem_set(void * dest, picopal_uint8 byte_val, picopal_objsize_t length); + +/* safe versions */ +picopal_objsize_t picopal_vslprintf(picopal_char * dst, picopal_objsize_t siz, const picopal_char *fmt, va_list args); +picopal_objsize_t picopal_slprintf(picopal_char * dst, picopal_objsize_t siz, const picopal_char *fmt, /*args*/ ...); +picopal_objsize_t picopal_strlcpy(picopal_char *dst, const picopal_char *src, picopal_objsize_t siz); + +/*Fixed point computation*/ +/* +picopal_int32 picopal_fixptdiv(picopal_int32 a, picopal_int32 b, picopal_uint8 bigpow); +picopal_int32 picopal_fixptmult(picopal_int32 x, picopal_int32 y, picopal_uint8 bigpow); +picopal_int32 picopal_fixptdivORinv(picopal_int32 a, picopal_int32 b, picopal_int32 invb, picopal_uint8 bigpow); +picopal_int32 picopal_fixptmultdouble(picopal_int32 x, picopal_int32 y, picopal_uint8 bigpow); +picopal_uint8 picopal_highestBit(picopal_int32 x); +*/ + +/* *************************************************/ +/* math */ +/* *************************************************/ + +picopal_double picopal_cos (const picopal_double cos_arg); +picopal_double picopal_sin (const picopal_double sin_arg); +picopal_double picopal_fabs (const picopal_double fabs_arg); + + + + +/* *************************************************/ +/* file access */ +/* *************************************************/ + +extern picopal_char picopal_eol(void); + +#define picopal_FILE FILE + + +/* seek modes to be used with the 'FSeek' procedure */ +#define PICOPAL_SEEK_SET 0 /* absolut seek position */ +#define PICOPAL_SEEK_CUR 1 /* relative to current */ +#define PICOPAL_SEEK_END 2 /* relative to the end of the file */ + + +typedef enum {PICOPAL_BINARY_READ, PICOPAL_BINARY_WRITE, PICOPAL_TEXT_READ, PICOPAL_TEXT_WRITE} picopal_access_mode; + +typedef picopal_FILE * picopal_File; + +extern picopal_File picopal_fopen (picopal_char fileName[], picopal_access_mode mode); +/* 'FOpen' opens the file with name 'filename'. Depending on + 'mode' : + 'TextRead' : Opens an existing text file for reading. + The file is positioned at the beginning of the file. + 'TextWrite' : Opens and truncates an existing file or creates a new + text file for writing. The file is positioned at the + beginning. + 'BinaryRead' : Opens an existing binary file for reading. + The file is positioned at the beginning of the file. + 'BinaryWrite' : Opens and truncates an existing file or creates a new + binary file for writing. The file is positioned at the + beginning. + If the opening of the file is successful a file pointer is given + back. Otherwise a NIL-File is given back. +*/ + + +extern picopal_File picopal_get_fnil (void); + + +extern picopal_int8 picopal_is_fnil (picopal_File f); + + +extern pico_status_t picopal_fclose (picopal_File f); + + +extern picopal_uint32 picopal_flength (picopal_File f); + + +extern picopal_uint8 picopal_feof (picopal_File f); + + +extern pico_status_t picopal_fseek (picopal_File f, picopal_uint32 offset, picopal_int8 seekmode); + + +extern pico_status_t picopal_fget_char (picopal_File f, picopal_char * ch); + + +extern picopal_objsize_t picopal_fread_bytes (picopal_File f, void * ptr, picopal_objsize_t objsize, picopal_uint32 nobj); + +extern picopal_objsize_t picopal_fwrite_bytes (picopal_File f, void * ptr, picopal_objsize_t objsize, picopal_uint32 nobj); + + +extern pico_status_t picopal_fflush (picopal_File f); + +/* +extern pico_status_t picopal_fput_char (picopal_File f, picopal_char ch); +*/ + + +/* +extern pico_status_t picopal_remove (picopal_char filename[]); + + +extern pico_status_t picopal_rename (picopal_char oldname[], picopal_char newname[]); + +*/ + +/* *************************************************/ +/* functions for debugging/testing purposes only */ +/* *************************************************/ + +/** + * Returns a pointer to a newly allocated chunk of 'size' bytes, aligned + * to the system page size. + * Memory allocated by this routine may be protected by calling function + * picopal_mrp_protect(). + */ +void *picopal_mpr_alloc(picopal_objsize_t size); + +/** + * Releases the chunk of memory pointed to by '*p'. 'p' must be previously + * allocated by a call to picopal_mpr_alloc(). + */ +void picopal_mpr_free(void **p); + +#define PICOPAL_PROT_NONE 0 /* the memory cannot be accessed at all */ +#define PICOPAL_PROT_READ 1 /* the memory can be read */ +#define PICOPAL_PROT_WRITE 2 /* the memory can be written to */ + +/** + * Specifies the desired protection 'prot' for the memory page(s) containing + * part or all of the interval [addr, addr+len-1]. If an access is disallowed + * by the protection given it, the program receives a SIGSEGV. + */ +pico_status_t picopal_mpr_protect(void *addr, picopal_objsize_t len, picopal_int16 prot); + +/* Fast, Compact Approximation of the Exponential Function */ +picopal_double picopal_quick_exp(const picopal_double y); + +/* *************************************************/ +/* types functions for time measurement */ +/* *************************************************/ + +extern void picopal_get_timer(picopal_uint32 * sec, picopal_uint32 * usec); + +#ifdef __cplusplus +} +#endif + + +#endif /*PICOPAL_H_*/ diff --git a/pico/lib/picopam.c b/pico/lib/picopam.c new file mode 100644 index 0000000..d52ab49 --- /dev/null +++ b/pico/lib/picopam.c @@ -0,0 +1,4810 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picopam.c + * + * Phonetic to Acoustic Mapping PU - Implementation + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include "picodefs.h" +#include "picoos.h" +#include "picodbg.h" +#include "picodata.h" +#include "picopam.h" +#include "picokdt.h" +#include "picokpdf.h" +#include "picoktab.h" +#include "picokdbg.h" +#include "picodsp.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +#define PICOPAM_IN_BUFF_SIZE PICODATA_BUFSIZE_PAM /*input buffer size for PAM */ +#define PICOPAM_OUT_PAM_SIZE PICODATA_BUFSIZE_PAM /*output buffer size for PAM*/ +#define PICOPAM_DT_NRLFZ 5 /* nr of lfz decision trees per phoneme */ +#define PICOPAM_DT_NRMGC 5 /* nr of mgc decision trees per phoneme */ +#define PICOPAM_NRSTPF 5 /* nr of states per phone */ + +#define PICOPAM_COLLECT 0 +#define PICOPAM_SCHEDULE 1 +#define PICOPAM_IMMEDIATE 2 +#define PICOPAM_FORWARD 3 +#define PICOPAM_FORWARD_FORCE_TERM 4 +#define PICOPAM_PROCESS 5 +#define PICOPAM_PLAY 6 +#define PICOPAM_FEED 7 + +#define PICOPAM_CONTINUE 100 +#define PICOPAM_GOTO_SCHEDULE 1 +#define PICOPAM_FLUSH_RECEIVED 6 +#define PICOPAM_GOTO_FEED 7 +#define PICOPAM_PRE_SYLL_ENDED 10 + +#define PICOPAM_BREAK_ADD_SIZE 4 /*syllable feature vector increment dued to BREAK and SILENCE*/ +#define PICOPAM_VECT_SIZE 64+PICOPAM_BREAK_ADD_SIZE /*syllable feature vector size (bytes)*/ +#define PICOPAM_INVEC_SIZE 60 /*phone feature vector size */ +#define PICOPAM_MAX_SYLL_PER_SENT 100 /*maximum number of syllables per sentece*/ +#define PICOPAM_MAX_PH_PER_SENT 400 /*maximum number of phonemes per sentece*/ +#define PICOPAM_MAX_ITEM_PER_SENT 255 /*maximum number of attached items per sentence*/ +#define PICOPAM_MAX_ITEM_SIZE_PER_SENT 4096 /*maximum size of attached items per sentence*/ + +#define PICOPAM_READY 20 /*PAM could start backward processing*/ +#define PICOPAM_MORE 21 /*PAM has still to collect */ +#define PICOPAM_NA 22 /*PAM has not to deal with this item*/ +#define PICOPAM_ERR 23 /*input item is not a valid item*/ + +/*sentence types:cfr pam_map_sentence_type*/ +#define PICOPAM_DECLARATIVE 0 +#define PICOPAM_INTERROGATIVE 1 +#define PICOPAM_EXCLAMATIVE 2 + +#define PICOPAM_T 0 +#define PICOPAM_P 1 +#define PICOPAM_p 2 +#define PICOPAM_Y 3 + +#if 1 +#define PAM_PHR2_WITH_PR1 1 /*deal with PHR2 boundaries as with PHR1*/ +#else +#define PAM_PHR2_WITH_PR3 1 /*deal with PHR2 boundaries as with PHR3*/ +#endif + +#define PICOPAM_DONT_CARE_VALUE 250 /*don't care value for tree printout */ +#define PICOPAM_DONT_CARE_VAL 10 /*don't care value for tree feeding */ +#define PICOPAM_PH_DONT_CARE_VAL 7 /*don't care value for tree feeding (phonetic)*/ + +#define PICOPAM_MAX_STATES_PER_PHONE 5 /*number of states per phone */ +#define PICOPAM_STATE_SIZE_IN_ITEM 6 /*size of a state in frame item */ +#define PICOPAM_FRAME_ITEM_SIZE 4+PICOPAM_MAX_STATES_PER_PHONE*PICOPAM_STATE_SIZE_IN_ITEM + +#define PICOPAM_DIR_FORW 0 /*forward adapter processing*/ +#define PICOPAM_DIR_BACK 1 /*backward adapter processing*/ +#define PICOPAM_DIR_SIL 2 /*final silence attributes*/ + +#define PICOPAM_SYLL_PAUSE 0 /*syllable but containing a pause phone*/ +#define PICOPAM_SYLL_SYLL 1 /*a real syllable with phonemes*/ + +#define PICOPAM_EVENT_P_BOUND 0 /*primary boundary*/ +#define PICOPAM_EVENT_S_BOUND 1 /*secondary boundary*/ +#define PICOPAM_EVENT_W_BOUND 3 /*word boundary*/ +#define PICOPAM_EVENT_SYLL 4 /*syllable*/ + +/* ----- CONSTANTS FOR BREAK COMMAND SUPPORT ----- */ +#define PICOPAM_PWIDX_SBEG 0 +#define PICOPAM_PWIDX_PHR1 1 +#define PICOPAM_PWIDX_PHR2 2 +#define PICOPAM_PWIDX_SEND 3 +#define PICOPAM_PWIDX_DEFA 4 +#define PICOPAM_PWIDX_SIZE 5 + +/*----------------------------------------------------------------*/ +/*structure related to the feature vectors for feeding the trees */ +/*NOTE : the same data structure is used to manage the syllables */ +/* Using the first 8 fields for marking the boundaries */ +/* and using the last 4 bytes as follows */ +/* byte 61 : 1st attached non PAM item id(0=no item attached) */ +/* in the "sSyllItemOffs" data structure */ +/* byte 62 : last attached non PAM item id(0=no item attached)*/ +/* in the "sSyllItemOffs" data structure */ +/* byte 63..64 : offset of the start of the syllable in */ +/* the "sPhIds" data structure */ +typedef struct +{ + picopal_uint8 phoneV[PICOPAM_VECT_SIZE]; +} sFtVect, *pSftVect; + +/*---------------------------------------------------------- + Name : pam_subobj + Function: subobject definition for the pam processing + Shortcut: pam + ---------------------------------------------------------*/ +typedef struct pam_subobj +{ + /*----------------------PU voice management------------------------------*/ + /* picorsrc_Voice voice; */ + /*----------------------PU state management------------------------------*/ + picoos_uint8 procState; /* where to take up work at next processing step */ + picoos_uint8 retState; /* where to go back from feed state at next p.s. */ + picoos_uint8 needMoreInput; /* more data necessary to start processing */ + /*----------------------PU input management------------------------------*/ + picoos_uint8 inBuf[PICOPAM_IN_BUFF_SIZE]; /* internal input buffer */ + picoos_uint16 inBufSize; /* actually allocated size */ + picoos_uint16 inReadPos, inWritePos; /* next pos to read/write from/to inBuf*/ + /*----------------------PU output management-----------------------------*/ + picoos_uint8 outBuf[PICOPAM_OUT_PAM_SIZE]; /* internal output buffer */ + picoos_uint16 outBufSize; /* actually allocated size */ + picoos_uint16 outReadPos, outWritePos; /* next pos to read/write from/to outBuf*/ + /*---------------------- adapter working buffers --------------------*/ + picoos_uint8 *sPhFeats; /*feature vector for a single phone */ + sFtVect *sSyllFeats; /*Syllable feature vector set for the + full sentence */ + picoos_uint8 *sPhIds; /*phone ids for the full sentence */ + picoos_uint8 *sSyllItems; /*items attached to the syllable */ + picoos_int16 *sSyllItemOffs;/*offset of items attached to the syllable*/ + /*---------------------- adapter general variables ---------------------*/ + picoos_int16 nTotalPhonemes; /*number of phonemes in the sentence*/ + picoos_int16 nCurrPhoneme; /*current phoneme in the sentence */ + picoos_int16 nSyllPhoneme; /*current phoneme in the syllable */ + picoos_int16 nCurrSyllable; /*current syllable in the sentence */ + picoos_int16 nTotalSyllables; /*number of syllables in the sentence -> J1*/ + picoos_uint8 nLastAttachedItemId;/*last attached item id*/ + picoos_uint8 nCurrAttachedItem; /*current attached item*/ + picoos_int16 nAttachedItemsSize; /*total size of the attached items*/ + picoos_uint8 sType; /*Sentence type*/ + picoos_uint8 pType; /*Phrase type*/ + picoos_single pMod; /*pitch modifier*/ + picoos_single dMod; /*Duration modifier*/ + picoos_single dRest; /*Duration modifier rest*/ + /*---------------------- adapter specific component variables ----------*/ + picoos_uint8 a3_overall_syllable; /* A3 */ + picoos_uint8 a3_primary_phrase_syllable; + picoos_uint8 b4_b5_syllable; /* B4,B5 */ + picoos_uint8 b6_b7_syllable; /* B6,B7 */ + picoos_uint8 b6_b7_state; + picoos_uint8 b8_b9_stressed_syllable; /* B8,B9 */ + picoos_uint8 b10_b11_accented_syllable; /* B10,B11 */ + picoos_uint8 b12_b13_syllable; /* B12,B13 */ + picoos_uint8 b12_b13_state; + picoos_uint8 b14_b15_syllable; /* B14,B15 */ + picoos_uint8 b14_b15_state; + picoos_uint8 b17_b19_syllable; /* B17,B19 */ + picoos_uint8 b17_b19_state; + picoos_uint8 b18_b20_b21_syllable; /* B18,B20,B21 */ + picoos_uint8 b18_b20_b21_state; + picoos_uint8 c3_overall_syllable; /* C3 */ + picoos_uint8 c3_primary_phrase_syllable; + picoos_uint8 d2_syllable_in_word; /* D2 */ + picoos_uint8 d2_prev_syllable_in_word; + picoos_uint8 d2_current_primary_phrase_word; + picoos_int8 e1_syllable_word_start; /* E1 */ + picoos_int8 e1_syllable_word_end; + picoos_uint8 e1_content; + picoos_int8 e2_syllable_word_start; /* E2 */ + picoos_int8 e2_syllable_word_end; + picoos_uint8 e3_e4_word; /* E3,E4 */ + picoos_uint8 e3_e4_state; + picoos_uint8 e5_e6_content_word; /* E5,E6 */ + picoos_uint8 e5_e6_content; + picoos_uint8 e7_e8_word; /* E7,E8 */ + picoos_uint8 e7_e8_content; + picoos_uint8 e7_e8_state; + picoos_uint8 e9_e11_word; /* E9,E11 */ + picoos_uint8 e9_e11_saw_word; + picoos_uint8 e9_e11_state; + picoos_uint8 e10_e12_e13_word; /* E10,E12,E13 */ + picoos_uint8 e10_e12_e13_state; + picoos_uint8 e10_e12_e13_saw_word; + picoos_uint8 f2_overall_word; /* F2 */ + picoos_uint8 f2_word_syllable; + picoos_uint8 f2_next_word_syllable; + picoos_uint8 f2_current_primary_phrase_word; + picoos_int8 g1_current_secondary_phrase_syllable; /*G1 */ + picoos_int8 g1_current_syllable; + picoos_int8 g2_current_secondary_phrase_word; /*G2 */ + picoos_int8 g2_current_word; + picoos_uint8 h1_current_secondary_phrase_syll; /*H1 */ + picoos_uint8 h2_current_secondary_phrase_word; /*H2 */ + picoos_uint8 h3_h4_current_secondary_phrase_word; /*H3,H4 */ + picoos_uint8 h5_current_phrase_type; /*H5 */ + + picoos_uint8 h5_syllable; /* H5 */ + picoos_uint8 h5_state; + + picoos_uint8 i1_secondary_phrase_syllable; /*I1 */ + picoos_uint8 i1_next_secondary_phrase_syllable; + picoos_uint8 i2_secondary_phrase_word; /*I2 */ + picoos_uint8 i2_next_secondary_phrase_word; + picoos_uint8 j1_utterance_syllable; /*J1 */ + picoos_uint8 j2_utterance_word; /*J2 */ + picoos_uint8 j3_utterance_sec_phrases; /*J3 */ + /*---------------------- constant data -------------------*/ + picoos_uint16 sil_weights[PICOPAM_PWIDX_SIZE][PICOPAM_MAX_STATES_PER_PHONE]; + /*---------------------- LINGWARE related data -------------------*/ + picokdt_DtPAM dtdur; /* dtdur knowledge base */ + picokdt_DtPAM dtlfz[PICOPAM_DT_NRLFZ]; /* dtlfz knowledge bases */ + picokdt_DtPAM dtmgc[PICOPAM_DT_NRMGC]; /* dtmgc knowledge bases */ + /*---------------------- Pdfs related data -------------------*/ + picokpdf_PdfDUR pdfdur; /* pdfdur knowledge base */ + picokpdf_PdfMUL pdflfz; /* pdflfz knowledge base */ + /*---------------------- Tree traversal related data -------------------*/ + picoos_uint16 durIndex; + picoos_uint8 numFramesState[PICOPAM_DT_NRLFZ]; + picoos_uint16 lf0Index[PICOPAM_DT_NRLFZ]; + picoos_uint16 mgcIndex[PICOPAM_DT_NRMGC]; + /*---------------------- temps for updating the feature vector ---------*/ + picoos_uint16 phonDur; + picoos_single phonF0[PICOPAM_DT_NRLFZ]; + /*---------------------- Phones related data -------------------*/ + picoktab_Phones tabphones; +} pam_subobj_t; + + +/* ----- CONSTANTS FOR FEATURE VECTOR BUILDING (NOT PREFIXED WITH "PICOPAM_" FOR BREVITY) ----- */ +#define P1 0 /*field 1 of the input vector*/ +#define P2 1 +#define P3 2 +#define P4 3 +#define P5 4 +#define P6 5 +#define P7 6 +#define bnd 6 /*boundary type item associated to the syllable = P7 */ +#define P8 7 +#define A3 8 +#define B1 9 +#define B2 10 +#define B3 11 +#define B4 12 +#define B5 13 +#define B6 14 +#define B7 15 +#define B8 16 +#define B9 17 +#define B10 18 +#define B11 19 +#define B12 20 +#define B13 21 +#define B14 22 +#define B15 23 +#define B16 24 +#define B17 25 +#define B18 26 +#define B19 27 +#define B20 28 +#define B21 29 +#define C3 30 +#define D2 31 +#define E1 32 +#define E2 33 +#define E3 34 +#define E4 35 +#define E5 36 +#define E6 37 +#define E7 38 +#define E8 39 +#define E9 40 +#define E10 41 +#define E11 42 +#define E12 43 +#define E13 44 +#define F2 45 +#define G1 46 +#define G2 47 +#define H1 48 +#define H2 49 +#define H3 50 +#define H4 51 +#define H5 52 +#define I1 53 +#define I2 54 +#define J1 55 +#define J2 56 +#define J3 57 +#define DUR 58 /*duration component*/ +#define F0 59 /*F0 component*/ +#define ITM 60 /*Item Offset into sSyllItems item list*/ +#define itm 61 /*second byte of the Item Offset */ +#define FID 62 /*Phoneme offset in the sPhIds phoneme list*/ +#define fid 63 /*second byte of the Phoneme offset */ +#define Min 64 /*offset to min syllable duration (uint 16,pauses)*/ +#define Max 66 /*offset to max syllable duration (uint 16,pauses)*/ +/* ------------------------------------------------------------------- + PAM feature vector indices position changes, + ------------------------------------------------------------------- */ +#define T_B1 8 +#define T_B2 9 +#define T_B3 10 +#define T_B4 11 +#define T_B5 12 +#define T_B6 13 +#define T_B7 14 +#define T_B8 15 +#define T_B9 16 +#define T_B10 17 +#define T_B11 18 +#define T_B12 19 +#define T_B13 20 +#define T_B14 21 +#define T_B15 22 +#define T_B16 23 +#define T_B17 24 +#define T_B18 25 +#define T_B19 26 +#define T_B20 27 +#define T_B21 28 +#define T_E1 29 +#define T_E2 30 +#define T_E3 31 +#define T_E4 32 +#define T_E5 33 +#define T_E6 34 +#define T_E7 35 +#define T_E8 36 +#define T_E9 37 +#define T_E10 38 +#define T_E11 39 +#define T_E12 40 +#define T_E13 41 +#define T_A3 42 +#define T_C3 43 +#define T_D2 44 +#define T_F2 45 +#define T_G1 46 +#define T_I1 47 +#define T_G2 48 +#define T_I2 49 +#define T_H1 50 +#define T_H2 51 +#define T_H3 52 +#define T_H4 53 +#define T_H5 54 + +/*------------------------------------------------------------------ + Service routines : + ------------------------------------------------------------------*/ +static pico_status_t pam_initialize(register picodata_ProcessingUnit this, picoos_int32 resetMode); +static pico_status_t pam_terminate(register picodata_ProcessingUnit this); +static pico_status_t pam_allocate(picoos_MemoryManager mm, pam_subobj_t *pam); +static void pam_deallocate(picoos_MemoryManager mm, pam_subobj_t *pam); +static pico_status_t pam_subobj_deallocate(register picodata_ProcessingUnit this, + picoos_MemoryManager mm); +/*------------------------------------------------------------------ + Processing routines : + ------------------------------------------------------------------*/ +static picodata_step_result_t pam_step(register picodata_ProcessingUnit this, + picoos_int16 mode, picoos_uint16 * numBytesOutput); +static pico_status_t pam_deal_with(const picoos_uint8 *item); +/*Utility*/ +static picoos_uint8 pam_get_vowel_name(register picodata_ProcessingUnit this, + picoos_uint8 *item, picoos_uint8 *pos); +static picoos_uint8 pam_get_pause_id(register picodata_ProcessingUnit this); + +static picoos_uint8 pam_map_sentence_type(picoos_uint8 iteminfo1, + picoos_uint8 iteminfo2); +static picoos_uint8 pam_map_phrase_type(picoos_uint8 iteminfo1, + picoos_uint8 iteminfo2); + +/*Adapter*/ +static pico_status_t pam_reset_processors(register picodata_ProcessingUnit this); +static pico_status_t pam_reset_processors_back( + register picodata_ProcessingUnit this); +static pico_status_t pam_create_syllable(register picodata_ProcessingUnit this, + picoos_uint8 syllType, picoos_uint8 *sContent, picoos_uint8 sentType, + picoos_uint8 phType, picoos_uint8 uBoundType, picoos_uint16 uMin, + picoos_uint16 uMax); +static pico_status_t pam_process_event_feature( + register picodata_ProcessingUnit this, picoos_uint8 nFeat, + picoos_uint8 event_type, picoos_uint8 direction); +static pico_status_t pam_process_event(register picodata_ProcessingUnit this, + picoos_uint8 event_type, picoos_uint8 direction); +static pico_status_t pam_adapter_forward_step( + register picodata_ProcessingUnit this, picoos_uint8 *itemBase); +static pico_status_t pam_adapter_backward_step( + register picodata_ProcessingUnit this); +static pico_status_t pam_do_pause(register picodata_ProcessingUnit this); +static pico_status_t pam_adapter_do_pauses(register picodata_ProcessingUnit this); +/*-------------- tree traversal ---------------------------------------*/ +static pico_status_t pam_expand_vector(register picodata_ProcessingUnit this); +static picoos_uint8 pam_do_tree(register picodata_ProcessingUnit this, + const picokdt_DtPAM dtpam, const picoos_uint8 *invec, + const picoos_uint8 inveclen, picokdt_classify_result_t *dtres); +static pico_status_t pam_get_f0(register picodata_ProcessingUnit this, + picoos_uint16 *lf0Index, picoos_uint8 nState, picoos_single *phonF0); +static pico_status_t pam_get_duration(register picodata_ProcessingUnit this, + picoos_uint16 durIndex, picoos_uint16 *phonDur, + picoos_uint8 *numFramesState); +static pico_status_t pam_update_vector(register picodata_ProcessingUnit this); +/*-------------- FINAL ITEM FEEDING -----------------------------------------*/ +static pico_status_t pam_put_item(register picodata_ProcessingUnit this, + picoos_uint8 *outBuff, picoos_uint16 outWritePos, + picoos_uint8 *bytesWr); + +static pico_status_t pam_put_term(picoos_uint8 *outBuff, + picoos_uint16 outWritePos, picoos_uint8 *bytesWr); + +static pico_status_t is_pam_command(const picoos_uint8 *qItem); + +static void get_default_boundary_limit(picoos_uint8 uBoundType, + picoos_uint16 *uMinDur, picoos_uint16 *uMaxDur); + +/* ------------------------------------------------------------- + * Pico System functions + * ------------------------------------------------------------- + */ + +/** + * allocation for PAM memory on pam PU + * @param mm : handle to engine memory manager + * @param pam : handle to a pam struct + * @return PICO_OK : allocation successful + * @return PICO_ERR_OTHER : allocation errors + * @callgraph + * @callergraph + */ +static pico_status_t pam_allocate(picoos_MemoryManager mm, pam_subobj_t *pam) +{ + picoos_uint8 *data; + picoos_int16 *dataI; + + pam->sSyllFeats = NULL; + pam->sPhIds = NULL; + pam->sPhFeats = NULL; + pam->sSyllItems = NULL; + pam->sSyllItemOffs = NULL; + + /*----------------------------------------------------------------- + * PAM Local buffers ALLOCATION + ------------------------------------------------------------------*/ + /*PAM Local buffers*/ + data = (picopal_uint8 *) picoos_allocate(mm, sizeof(sFtVect) + * PICOPAM_MAX_SYLL_PER_SENT); + if (data == NULL) + return PICO_ERR_OTHER; + pam->sSyllFeats = (sFtVect*) data; + + data = (picopal_uint8 *) picoos_allocate(mm, sizeof(picopal_uint8) + * PICOPAM_MAX_PH_PER_SENT); + if (data == NULL) { + pam_deallocate(mm, pam); + return PICO_ERR_OTHER; + } + pam->sPhIds = (picopal_uint8*) data; + + data = (picopal_uint8 *) picoos_allocate(mm, sizeof(picopal_uint8) + * PICOPAM_VECT_SIZE); + if (data == NULL) { + pam_deallocate(mm, pam); + return PICO_ERR_OTHER; + } + pam->sPhFeats = (picopal_uint8*) data; + + data = (picopal_uint8 *) picoos_allocate(mm, sizeof(picopal_uint8) + * PICOPAM_MAX_ITEM_SIZE_PER_SENT); + if (data == NULL) { + pam_deallocate(mm, pam); + return PICO_ERR_OTHER; + } + pam->sSyllItems = (picopal_uint8*) data; + + dataI = (picoos_int16 *) picoos_allocate(mm, sizeof(picoos_int16) + * PICOPAM_MAX_ITEM_PER_SENT); + if (data == NULL) { + pam_deallocate(mm, pam); + return PICO_ERR_OTHER; + } + pam->sSyllItemOffs = (picoos_int16*) dataI; + + return PICO_OK; +}/*pam_allocate*/ + +/** + * frees allocation for DSP memory on PAM PU + * @param mm : memory manager + * @param pam : pam PU internal sub-object + * @return void + * @remarks modified and inserted in sub obj removal PP 15.09.08 + * @callgraph + * @callergraph + */ +static void pam_deallocate(picoos_MemoryManager mm, pam_subobj_t *pam) +{ + /*----------------------------------------------------------------- + * Memory de-allocations + * ------------------------------------------------------------------*/ + if (pam->sSyllFeats != NULL) + picoos_deallocate(mm, (void *) &pam->sSyllFeats); + if (pam->sPhIds != NULL) + picoos_deallocate(mm, (void *) &pam->sPhIds); + if (pam->sPhFeats != NULL) + picoos_deallocate(mm, (void *) &pam->sPhFeats); + if (pam->sSyllItems != NULL) + picoos_deallocate(mm, (void *) &pam->sSyllItems); + if (pam->sSyllItemOffs != NULL) + picoos_deallocate(mm, (void *) &pam->sSyllItemOffs); + +}/*pam_deallocate*/ + +/** + * initialization of a pam PU + * @param this : handle to a PU struct + * @return PICO_OK : init OK + * @return PICO_ERR_OTHER : error on getting pkbs addresses + * @callgraph + * @callergraph + */ +static pico_status_t pam_initialize(register picodata_ProcessingUnit this, picoos_int32 resetMode) +{ + pico_status_t nI, nJ; + pam_subobj_t *pam; + + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + pam = (pam_subobj_t *) this->subObj; + pam->inBufSize = PICOPAM_IN_BUFF_SIZE; + pam->outBufSize = PICOPAM_OUT_PAM_SIZE; + pam->inReadPos = 0; + pam->inWritePos = 0; + pam->outReadPos = 0; + pam->outWritePos = 0; + pam->needMoreInput = 0; + pam->procState = 0; + + /*----------------------------------------------------------------- + * MANAGE INTERNAL INITIALIZATION + ------------------------------------------------------------------*/ + /*init the syllable structure*/ + for (nI = 0; nI < PICOPAM_MAX_SYLL_PER_SENT; nI++) + for (nJ = 0; nJ < PICOPAM_VECT_SIZE; nJ++) + pam->sSyllFeats[nI].phoneV[nJ] = 0; + + for (nI = 0; nI < PICOPAM_MAX_PH_PER_SENT; nI++) + pam->sPhIds[nI] = 0; + + for (nI = 0; nI < PICOPAM_VECT_SIZE; nI++) + pam->sPhFeats[nI] = 0; + + for (nI = 0; nI < PICOPAM_MAX_ITEM_SIZE_PER_SENT; nI++) + pam->sSyllItems[nI] = 0; + + for (nI = 0; nI < PICOPAM_MAX_ITEM_PER_SENT; nI++) + pam->sSyllItemOffs[nI] = 0; + + /*Other variables*/ + pam_reset_processors(this); + pam->nLastAttachedItemId = pam->nCurrAttachedItem = 0; + pam->nAttachedItemsSize = 0; + + if (resetMode == PICO_RESET_SOFT) { + /*following initializations needed only at startup or after a full reset*/ + return PICO_OK; + } + + /*pitch and duration modifiers*/ + pam->pMod = 1.0f; + pam->dMod = 1.0f; + pam->dRest = 0.0f; + + + /* constant tables */ + { + picoos_uint8 i, j; + picoos_uint16 tmp_weights[PICOPAM_PWIDX_SIZE][PICOPAM_MAX_STATES_PER_PHONE] = { + {10, 10, 10, 10, 1 }, /*SBEG*/ + { 1, 4, 8, 4, 1 }, /*PHR1*/ + { 1, 4, 8, 4, 1 }, /*PHR2*/ + { 1, 10, 10, 10, 10 },/*SEND*/ + { 1, 1, 1, 1, 1 } /*DEFAULT*/ + }; + for (i = 0; i < PICOPAM_PWIDX_SIZE; i++) { + for (j = 0; j < PICOPAM_PWIDX_SIZE; j++) { + pam->sil_weights[j][j] = tmp_weights[i][j]; + } + } + } + + +/*----------------------------------------------------------------- + * MANAGE LINGWARE INITIALIZATION IF NEEDED + ------------------------------------------------------------------*/ + /* kb dtdur */ + pam->dtdur = picokdt_getDtPAM(this->voice->kbArray[PICOKNOW_KBID_DT_DUR]); + if (pam->dtdur == NULL) { + picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, NULL, + NULL); + return PICO_ERR_OTHER; + }PICODBG_DEBUG(("got dtdur")); + + /* kb dtlfz* */ + pam->dtlfz[0] = picokdt_getDtPAM( + this->voice->kbArray[PICOKNOW_KBID_DT_LFZ1]); + pam->dtlfz[1] = picokdt_getDtPAM( + this->voice->kbArray[PICOKNOW_KBID_DT_LFZ2]); + pam->dtlfz[2] = picokdt_getDtPAM( + this->voice->kbArray[PICOKNOW_KBID_DT_LFZ3]); + pam->dtlfz[3] = picokdt_getDtPAM( + this->voice->kbArray[PICOKNOW_KBID_DT_LFZ4]); + pam->dtlfz[4] = picokdt_getDtPAM( + this->voice->kbArray[PICOKNOW_KBID_DT_LFZ5]); + for (nI = 0; nI < PICOPAM_DT_NRLFZ; nI++) { + if (pam->dtlfz[nI] == NULL) { + picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + return PICO_ERR_OTHER; + }PICODBG_DEBUG(("got dtlfz%d", nI+1)); + } + + /* kb dtmgc* */ + pam->dtmgc[0] = picokdt_getDtPAM( + this->voice->kbArray[PICOKNOW_KBID_DT_MGC1]); + pam->dtmgc[1] = picokdt_getDtPAM( + this->voice->kbArray[PICOKNOW_KBID_DT_MGC2]); + pam->dtmgc[2] = picokdt_getDtPAM( + this->voice->kbArray[PICOKNOW_KBID_DT_MGC3]); + pam->dtmgc[3] = picokdt_getDtPAM( + this->voice->kbArray[PICOKNOW_KBID_DT_MGC4]); + pam->dtmgc[4] = picokdt_getDtPAM( + this->voice->kbArray[PICOKNOW_KBID_DT_MGC5]); + for (nI = 0; nI < PICOPAM_DT_NRMGC; nI++) { + if (pam->dtmgc[nI] == NULL) { + picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + return PICO_ERR_OTHER; + }PICODBG_DEBUG(("got dtmgc%d", nI+1)); + } + + /* kb pdfdur* */ + pam->pdfdur = picokpdf_getPdfDUR( + this->voice->kbArray[PICOKNOW_KBID_PDF_DUR]); + if (pam->pdfdur == NULL) { + picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, NULL, + NULL); + return PICO_ERR_OTHER; + }PICODBG_DEBUG(("got pdfdur")); + + /* kb pdflfz* */ + pam->pdflfz = picokpdf_getPdfMUL( + this->voice->kbArray[PICOKNOW_KBID_PDF_LFZ]); + if (pam->pdflfz == NULL) { + picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, NULL, + NULL); + return PICO_ERR_OTHER; + }PICODBG_DEBUG(("got pdflfz")); + + /* kb tabphones */ + pam->tabphones = picoktab_getPhones( + this->voice->kbArray[PICOKNOW_KBID_TAB_PHONES]); + if (pam->tabphones == NULL) { + picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, NULL, + NULL); + return PICO_ERR_OTHER; + }PICODBG_DEBUG(("got tabphones")); + + return PICO_OK; +}/*pam_initialize*/ + +/** + * termination of a pam PU + * @param this : handle to a pam PU struct + * @return PICO_OK + * @callgraph + * @callergraph + */ +static pico_status_t pam_terminate(register picodata_ProcessingUnit this) +{ + + pam_subobj_t *pam; + + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + pam = (pam_subobj_t *) this->subObj; + + return PICO_OK; +}/*pam_terminate*/ + +/** + * deallocaton of a pam PU + * @param this : handle to a pam PU struct + * @param mm : engine memory manager + * @return PICO_OK + * @callgraph + * @callergraph + */ +static pico_status_t pam_subobj_deallocate(register picodata_ProcessingUnit this, + picoos_MemoryManager mm) +{ + + pam_subobj_t* pam; + + if (NULL != this) { + pam = (pam_subobj_t *) this->subObj; + mm = mm; /* avoid warning "var not used in this function"*/ + /*----------------------------------------------------------------- + * Memory de-allocations + * ------------------------------------------------------------------*/ + if (pam->sSyllFeats != NULL) { + picoos_deallocate(this->common->mm, (void *) &pam->sSyllFeats); + } + if (pam->sPhIds != NULL) { + picoos_deallocate(this->common->mm, (void *) &pam->sPhIds); + } + if (pam->sPhFeats != NULL) { + picoos_deallocate(this->common->mm, (void *) &pam->sPhFeats); + } + if (pam->sSyllItems != NULL) { + picoos_deallocate(this->common->mm, (void *) &pam->sSyllItems); + } + if (pam->sSyllItemOffs != NULL) { + picoos_deallocate(this->common->mm, (void *) &pam->sSyllItemOffs); + } + picoos_deallocate(this->common->mm, (void *) &this->subObj); + } + + return PICO_OK; +}/*pam_subobj_deallocate*/ + +/** + * creates a new pam processing unit + * @param mm : engine memory manager + * @param common : engine common object pointer + * @param cbIn : pointer to input buffer + * @param cbOut : pointer to output buffer + * @param voice : pointer to voice structure + * @return this : pam PU handle if success + * @return NULL : if error + * @callgraph + * @callergraph + */ +picodata_ProcessingUnit picopam_newPamUnit(picoos_MemoryManager mm, + picoos_Common common, picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, picorsrc_Voice voice) +{ + + register pam_subobj_t * pam; + + picodata_ProcessingUnit this = picodata_newProcessingUnit(mm, common, cbIn, + cbOut, voice); + if (this == NULL) { + return NULL; + } + this->initialize = pam_initialize; + + PICODBG_DEBUG(("picotok_newPamUnit -- set this->step to pam_step")); + + this->step = pam_step; + this->terminate = pam_terminate; + this->subDeallocate = pam_subobj_deallocate; + this->subObj = picoos_allocate(mm, sizeof(pam_subobj_t)); + if (this->subObj == NULL) { + PICODBG_ERROR(("Error in Pam Object allocation")); + picoos_deallocate(mm, (void*) &this); + return NULL; + }; + + /*----------------------------------------------------------------- + * Allocate internal memory for PAM (only at PU creation time) + * ------------------------------------------------------------------*/ + pam = (pam_subobj_t *) this->subObj; + if (PICO_OK != pam_allocate(mm, pam)) { + PICODBG_ERROR(("Error in Pam buffers Allocation")); + picoos_deallocate(mm, (void *) &this->subObj); + picoos_deallocate(mm, (void *) &this); + return NULL; + } + + /*----------------------------------------------------------------- + * Initialize memory for PAM (this may be re-used elsewhere, e.g.Reset) + * ------------------------------------------------------------------*/ + if (PICO_OK != pam_initialize(this, PICO_RESET_FULL)) { + PICODBG_ERROR(("problem initializing the pam sub-object")); + } + return this; +}/*picopam_newPamUnit*/ + +/*------------------------------------------------------------------------------- + PROCESSING AND INTERNAL FUNCTIONS + --------------------------------------------------------------------------------*/ + +/** + * initializes default duration limits for boundary items + * @param uBoundType : type of input boundary type + * @param *uMinDur, *uMaxDur : addresses of values to initialize + * @return void + * @remarks so far initializes to 0 both values; this will leave the values given by tree prediction + * @callgraph + * @callergraph + */ +static void get_default_boundary_limit(picoos_uint8 uBoundType, + picoos_uint16 *uMinDur, picoos_uint16 *uMaxDur) +{ + switch (uBoundType) { + case PICODATA_ITEMINFO1_BOUND_SBEG: + *uMinDur = 0; + *uMaxDur = 20; + break; + case PICODATA_ITEMINFO1_BOUND_SEND: + *uMinDur = 550; + *uMaxDur = 650; + break; + case PICODATA_ITEMINFO1_BOUND_TERM: + *uMinDur = 0; + *uMaxDur = 0; + break; + case PICODATA_ITEMINFO1_BOUND_PHR0: + *uMinDur = 0; + *uMaxDur = 0; + break; + case PICODATA_ITEMINFO1_BOUND_PHR1: + *uMinDur = 275; + *uMaxDur = 325; + break; + case PICODATA_ITEMINFO1_BOUND_PHR2: + *uMinDur = 4; + *uMaxDur = 60; + break; + case PICODATA_ITEMINFO1_BOUND_PHR3: + *uMinDur = 0; + *uMaxDur = 0; + break; + default: + break; + } + +}/*get_default_boundary_limit*/ + +/** + * checks if "neededSize" is available on "nCurrPhoneme" + * @param pam : pam subobj + * @param neededSize : the requested size + * @return PICO_OK : size is available + * @return !=PICO_OK : size not available + * @callgraph + * @callergraph + */ +static pico_status_t check_phones_size(pam_subobj_t *pam, + picoos_int16 neededSize) +{ + if ((pam->nCurrPhoneme + neededSize) > PICOPAM_MAX_PH_PER_SENT - 1) { + return PICO_ERR_OTHER; + } + return PICO_OK; +}/*check_phones_size*/ + +/** + * checks if neededSize is available on "nCurrSyllable" + * @param pam : pam subobj + * @param neededSize : the requested size + * @return PICO_OK : size is available + * @return !=PICO_OK : size not available + * @callgraph + * @callergraph + */ +static pico_status_t check_syllables_size(pam_subobj_t *pam, + picoos_int16 neededSize) +{ + if ((pam->nCurrSyllable + neededSize) > PICOPAM_MAX_SYLL_PER_SENT - 1) { + return PICO_ERR_OTHER; + } + return PICO_OK; +}/*check_syllables_size*/ + +/** + * verifies that local storage has enough space to receive 1 item + * @param this : pointer to current PU struct + * @param item : pointer to current item head + * @return TRUE : resource limits would be reached during processing of input item + * @return FALSE : item could be processed normally + * @remarks item pointed to by *item should be already valid + * @callgraph + * @callergraph + */ +static pico_status_t pamCheckResourceLimits( + register picodata_ProcessingUnit this, const picoos_uint8 *item) +{ + register pam_subobj_t * pam; + picodata_itemhead_t head; + pico_status_t sResult; + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + pam = (pam_subobj_t *) this->subObj; + sResult = TRUE; /*default : resource limits reached*/ + head.type = item[0]; + head.info1 = item[1]; + head.info2 = item[2]; + head.len = item[3]; + + switch (head.type) { + /*commands that generate syllables/phonemes*/ + case PICODATA_ITEM_SYLLPHON: + if (pam->nCurrSyllable >= PICOPAM_MAX_SYLL_PER_SENT - 2) { + return sResult; /*no room for more syllables*/ + } + if ((pam->nCurrPhoneme + head.len) >= PICOPAM_MAX_PH_PER_SENT - 2) { + return sResult; /*no room for more phoneme*/ + } + break; + case PICODATA_ITEM_BOUND: + if ((head.info1 == PICODATA_ITEMINFO1_BOUND_SBEG) || (head.info1 + == PICODATA_ITEMINFO1_BOUND_SEND) || (head.info1 + == PICODATA_ITEMINFO1_BOUND_TERM) || (head.info1 + == PICODATA_ITEMINFO1_BOUND_PHR1) +#ifdef PAM_PHR2_WITH_PR1 + || (head.info1 == PICODATA_ITEMINFO1_BOUND_PHR2) +#endif + ) { + + if (pam->nCurrSyllable >= PICOPAM_MAX_SYLL_PER_SENT - 2) { + return sResult; /*no room for more syllables*/ + } + if ((pam->nCurrPhoneme + 1) >= PICOPAM_MAX_PH_PER_SENT - 2) { + return sResult; /*no room for more phoneme*/ + } + } + break; + + default: + /*all other commands has to be queued*/ + if ((pam->nAttachedItemsSize + head.len) + >= PICOPAM_MAX_ITEM_SIZE_PER_SENT - 1) { + return sResult; /*no room for more items*/ + } + break; + } + return FALSE; /*no resource limits apply to current item*/ +} /*pamCheckResourceLimits*/ + +/** + * selects items to be sent to next PU immedately + * @param this : pointer to current PU struct + * @param item : pointer to current item head + * @return TRUE : item should be passed on next PU NOW + * @return FALSE : item should not be passed on next PU now but should be processed + * @remarks item pointed to by *item should be already valid + * @callgraph + * @callergraph + */ +static pico_status_t pam_check_immediate(register picodata_ProcessingUnit this, + const picoos_uint8 *item) +{ + register pam_subobj_t * pam; + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + pam = (pam_subobj_t *) this->subObj; + + if (pam->nCurrSyllable <= -1) { + if (item[0] == PICODATA_ITEM_SYLLPHON) + return FALSE; + if ((item[0] == PICODATA_ITEM_BOUND) && (item[1] + == PICODATA_ITEMINFO1_BOUND_SBEG)) + return FALSE; + if (is_pam_command((picoos_uint8 *) item) == TRUE) + return FALSE; + return TRUE; /*no need to process data : send it*/ + } + return FALSE; /*syllable struct not void : do standard processing*/ + +} /*pam_check_immediate*/ + +/** + * checks if the input item has to be queued in local storage for later resynch + * @param this : pointer to current PU struct + * @param item : pointer to current item head + * @return TRUE : item should be queued + * @return FALSE : item should not be queued + * @remarks item pointed to by *item should be already valid + * @callgraph + * @callergraph + */ +static pico_status_t pam_hastobe_queued(register picodata_ProcessingUnit this, + const picoos_uint8 *item) +{ + register pam_subobj_t * pam; + picodata_itemhead_t head; + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + pam = (pam_subobj_t *) this->subObj; + head.type = item[0]; + head.info1 = item[1]; + + switch (head.type) { + /*commands that generate syllables/phonemes*/ + case PICODATA_ITEM_SYLLPHON: + return FALSE; /*no queue needed*/ + break; + case PICODATA_ITEM_BOUND: + if ((head.info1 == PICODATA_ITEMINFO1_BOUND_PHR3) +#ifdef PAM_PHR2_WITH_PR3 + ||(head.info1==PICODATA_ITEMINFO1_BOUND_PHR2) +#endif + || (head.info1 == PICODATA_ITEMINFO1_BOUND_PHR0)) { + return FALSE; /*no queue needed*/ + } + break; + + default: + /*all other items has to be queued*/ + break; + } + return TRUE; /*item has to be queued*/ +} /*pam_hastobe_queued*/ + +/** + * queue item in local storage for later resynch + * @param this : pointer to current PU struct + * @param item : pointer to current item head + * @return TRUE : item queued + * @return FALSE : item not queued because of errors + * @remarks item pointed to by *item should be already valid + * @callgraph + * @callergraph + */ +static pico_status_t pam_queue(register picodata_ProcessingUnit this, + const picoos_uint8 *item) +{ + register pam_subobj_t * pam; + picodata_itemhead_t head; + picoos_uint8 nI; + pico_status_t sResult; + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + pam = (pam_subobj_t *) this->subObj; + sResult = TRUE; /*default : item queued*/ + head.type = item[0]; + head.info1 = item[1]; + head.info2 = item[2]; + head.len = item[3]; + + /*test condition on enough room to store current item in the "sSyllItems" area*/ + if ((pam->nAttachedItemsSize + head.len + sizeof(picodata_itemhead_t)) + >= PICOPAM_MAX_ITEM_SIZE_PER_SENT - 1) { + return FALSE; /*resource limit reached*/ + } + /*store current offset*/ + pam->sSyllItemOffs[pam->nLastAttachedItemId] = pam->nAttachedItemsSize; + /*store the item to the "sSyllItems" area*/ + for (nI = 0; nI < (head.len + sizeof(picodata_itemhead_t)); nI++) { + pam->sSyllItems[pam->nAttachedItemsSize + nI] = item[nI]; + } + /*increment the attached items area*/ + pam->nAttachedItemsSize += nI; + + /*increment id*/ + pam->nLastAttachedItemId++; + /*set start(if not initialized) and end ids of queued items in sSyllFeats*/ + if (pam->nCurrSyllable > -1) { + /*normal case : the item is attached to current syllable*/ + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[ITM] == 0) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[ITM] + = pam->nLastAttachedItemId; + } + pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm] + = pam->nLastAttachedItemId; + } else { + /*special case : an item is requested to be queued even if no + syllables has been assigned to the sentence structure : + -->> use syll 0*/ + if (pam->sSyllFeats[0].phoneV[ITM] == 0) { + pam->sSyllFeats[0].phoneV[ITM] = pam->nLastAttachedItemId; + } + pam->sSyllFeats[0].phoneV[itm] = pam->nLastAttachedItemId; + } + return TRUE; /*item queued successfully*/ +} /*pam_queue*/ + +/** + * selects items to be dealth with by the PU processing + * @param item : pointer to current item head + * @return TRUE : item should be processed + * @return FALSE : item should not be processed (maybe it ontains commands or items for other PUs) + * @remarks item pointed to by *item should be already valid + * @callgraph + * @callergraph + */ +static pico_status_t pam_deal_with(const picoos_uint8 *item) +{ + picodata_itemhead_t head; + pico_status_t sResult; + sResult = FALSE; + head.type = item[0]; + head.info1 = item[1]; + head.info2 = item[2]; + head.len = item[3]; + switch (head.type) { + case PICODATA_ITEM_SYLLPHON: + case PICODATA_ITEM_BOUND: + sResult = TRUE; + break; + default: + break; + } + return sResult; +} /*pam_deal_with*/ + +/** + * returns true if more items has to be produced for current syllable + * @param this : Pam object pointer + * @return TRUE : item is to be produced + * @return FALSE : item is not to be produced + * @remarks item pointed to by *item should be already valid + * @callgraph + * @callergraph + */ +static picoos_uint8 pamHasToProcess(register picodata_ProcessingUnit this) +{ + register pam_subobj_t * pam; + picoos_uint8 nCond1, nCond2, nCond3; + + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + pam = (pam_subobj_t *) this->subObj; + /*conditions originating a "NOT to be processed" result */ + nCond1 = pam->nCurrSyllable <= -1; + nCond2 = pam->nCurrSyllable >= pam->nTotalSyllables; + nCond3 = pam->nSyllPhoneme + >= pam->sSyllFeats[pam->nCurrSyllable].phoneV[B3]; + + if ((nCond1) || (nCond2) || (nCond3)) + return FALSE; + + return TRUE; +} /*pamHasToProcess*/ + +/** + * modifies the process flags in order to point to next valid syllable phone or item to be produced + * @param this : Pam object pointer + * @return TRUE : item has to be produced + * @return FALSE : item has not to be produced + * @callgraph + * @callergraph + */ +static pico_status_t pamUpdateProcess(register picodata_ProcessingUnit this) +{ + register pam_subobj_t * pam; + + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + pam = (pam_subobj_t *) this->subObj; + + if (pam->nCurrSyllable == -1) { + /*this to be able to manage sudden PU cleanup after FLUSH CMD*/ + return PICO_OK; + } + /*check number of phonemes for current syllable*/ + if (pam->nSyllPhoneme < pam->sSyllFeats[pam->nCurrSyllable].phoneV[B3] - 1) { + pam->nSyllPhoneme++; + return PICO_OK; + } + if (pam->nSyllPhoneme == pam->sSyllFeats[pam->nCurrSyllable].phoneV[B3] - 1) { + /*this helps in identifyng the end of syllable condition in PamHasToProcess*/ + pam->nSyllPhoneme++; + } + /*previous syllable phonemes are complete: test if any items are tied to this syllable*/ + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[ITM] > 0) { + /*there are items tied to this syllable*/ + if (pam->nCurrAttachedItem == 0) { + /*if it is the first item to be regenerated initialize it*/ + pam->nCurrAttachedItem + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[ITM]; + return PICO_OK; + } else { + /*not the first item : check if more*/ + if (pam->nCurrAttachedItem + < pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm]) { + /*more tied items to be regenerated*/ + pam->nCurrAttachedItem++; + return PICO_OK; + } + } + } + /*previous syllable phonemes and items are complete: switch to next syllable*/ + if (pam->nCurrSyllable < pam->nTotalSyllables - 1) { + pam->nCurrSyllable++; + pam->nSyllPhoneme = 0; + pam->nCurrAttachedItem = 0; + return PICO_OK; + } + /*no more phonemes or items to be produced*/ + pam->nCurrSyllable++; + pam->nSyllPhoneme = 0; + return PICO_ERR_OTHER; + +} /*pamUpdateProcess*/ + +/** + * returns true if more items has to be popped for current syllable + * @param this : Pam object pointer + * @return TRUE : item has to be popped + * @return FALSE : item has not to be popped + * @callgraph + * @callergraph + */ +static picoos_uint8 pamHasToPop(register picodata_ProcessingUnit this) +{ + register pam_subobj_t * pam; + + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + pam = (pam_subobj_t *) this->subObj; + + /*Preliminary condition : at least 1 syllable*/ + if (pam->nCurrSyllable <= -1) + return FALSE; + + /*Preliminary condition : not maximum number of syllables*/ + if (pam->nCurrSyllable >= pam->nTotalSyllables) + return FALSE; + + /*Preliminary condition : start and end offset in current item > 0 */ + if ((pam->sSyllFeats[pam->nCurrSyllable].phoneV[ITM] <= 0) + || (pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm] <= 0)) + return FALSE; + + /*Final condition : current popped item less or eq to maximum*/ + if (pam->nCurrAttachedItem + > pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm]) + return FALSE; + + return TRUE; +} /*pamHasToPop*/ + +/** + * returns the address of an item to be popped from the current syllable queue + * @param this : Pam object pointer + * @return pop_address : item address + * @return NULL : item not poppable + * @callgraph + * @callergraph + */ +static picoos_uint8 *pamPopItem(register picodata_ProcessingUnit this) +{ + register pam_subobj_t * pam; + picoos_uint8 nItem; + if (NULL == this || NULL == this->subObj) { + return NULL; + } + pam = (pam_subobj_t *) this->subObj; + + /*Preliminary condition : at least 1 syllable*/ + if (pam->nCurrSyllable <= -1) + return NULL; + + /*Preliminary condition : not maximum number of syllables*/ + if (pam->nCurrSyllable >= pam->nTotalSyllables) + return NULL; + + /*Preliminary condition : start and end offset in current item > 0 */ + if ((pam->sSyllFeats[pam->nCurrSyllable].phoneV[ITM] <= 0) + || (pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm] <= 0)) + return NULL; + + /*Final condition : current popped item less than maximum*/ + if (pam->nCurrAttachedItem + > pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm]) + return NULL; + + nItem = pam->nCurrAttachedItem; + /*please note : nItem-1 should match with actions performed in function "pam_queue(..)" */ + return &(pam->sSyllItems[pam->sSyllItemOffs[nItem - 1]]); + +} /*pamPopItem*/ + +/** + * returns the address of an item popped from the syllable 0 queue + * @param this : Pam object pointer + * @return pop_address : item address + * @return NULL : item not poppable + * @remarks the item is popped only if it has been inserted in the queue before the first + * @remarks item assigned to the syllable 0 i.e. + * @remarks AttachedItem<=pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm]-1 + * @callgraph + * @callergraph + */ +static picoos_uint8 *pamPopAttachedSy0(register picodata_ProcessingUnit this) +{ + register pam_subobj_t * pam; + picoos_uint8 nItem; + if (NULL == this || NULL == this->subObj) { + return NULL; + } + pam = (pam_subobj_t *) this->subObj; + + /*should be syllable 0*/ + if (pam->nCurrSyllable != 0) + return NULL; + + /*start and end offset in current item > 0 */ + if ((pam->sSyllFeats[pam->nCurrSyllable].phoneV[ITM] <= 0) + || (pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm] <= 0)) + return NULL; + + /*if current popped item is > 0 test end condition*/ + if (pam->nCurrAttachedItem > 0) { + /*Other condition : current popped item less than maximum*/ + if (pam->nCurrAttachedItem + > pam->sSyllFeats[pam->nCurrSyllable].phoneV[itm] - 1) + return NULL; + } + nItem = pam->nCurrAttachedItem; + return &(pam->sSyllItems[pam->sSyllItemOffs[nItem]]); + +} /*pamPopAttachedSy0*/ + +/** + * pdf access for duration + * @param this : Pam object pointer + * @param durIndex : index of duration in the pdf + * @param phonDur : pointer to base of array where to store the duration values + * @param numFramesState : pointer to base of array where to store the number of frames per state + * @return PICO_OK : pdf retrieved + * @return PICO_ERR_OTHER : pdf not retrieved + * @remarks Modifies phonDur (the requested duration value) + * @remarks Modifies numFramesState (the requested number of frames per state (vector)) + * @callgraph + * @callergraph + */ +static pico_status_t pam_get_duration(register picodata_ProcessingUnit this, + picoos_uint16 durIndex, picoos_uint16 *phonDur, + picoos_uint8 *numFramesState) +{ + pam_subobj_t *pam; + picokpdf_PdfDUR pdf; + picoos_uint8 *durItem; + picoos_uint16 nFrameSize, nI; + picoos_single fValue; + pam = (pam_subobj_t *) this->subObj; + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + pdf = pam->pdfdur; + /*make the index 0 based*/ + if (durIndex > 0) + durIndex--; + + /* check */ + if (durIndex > pdf->numframes - 1) { + PICODBG_ERROR(("PAM durPdf access error, index overflow -> index: %d , numframes: %d", durIndex, pdf->numframes)); + return PICO_ERR_OTHER; + } + /* base pointer */ + durItem = &(pdf->content[durIndex * pdf->vecsize]); + if (durItem == NULL) { + PICODBG_ERROR(("PAM durPdf access error , frame pointer = NULL")); + return PICO_ERR_OTHER; + } + nFrameSize = pdf->sampperframe / 16; + *phonDur = ((pdf->phonquant[((*durItem) & 0xF0) >> 4]) * nFrameSize); + numFramesState[0] = pdf->statequant[((*durItem) & 0x0F)]; + durItem++; + numFramesState[1] = pdf->statequant[((*durItem) & 0xF0) >> 4]; + numFramesState[2] = pdf->statequant[((*durItem) & 0x0F)]; + durItem++; + numFramesState[3] = pdf->statequant[((*durItem) & 0xF0) >> 4]; + numFramesState[4] = pdf->statequant[((*durItem) & 0x0F)]; + + /*modification of the duration information based on the duration modifier*/ + *phonDur = (picoos_uint16) (((picoos_single) * phonDur) * pam->dMod); + for (nI = 0; nI < 5; nI++) { + fValue = pam->dRest + (picoos_single) numFramesState[nI] * pam->dMod; + numFramesState[nI] = (picoos_uint8) (fValue); + pam->dRest = fValue - (picoos_single) numFramesState[nI]; + } + return PICO_OK; +}/*pam_get_duration*/ + +/** + * pdf access for pitch + * @param this : Pam object pointer + * @param lf0Index : pointer to variable to receive index of pitch in the pdf + * @param nI : number of the phone's state + * @param phonF0 : pointer to variable to receive the pitch value + * @return PICO_OK : pdf retrieved + * @return PICO_ERR_OTHER : pdf not retrieved + * @remarks Modifies phonDur (the requested duration value) + * @remarks Modifies phonF0 (the requested pitch value (scalar)) + * @callgraph + * @callergraph + */ +static pico_status_t pam_get_f0(register picodata_ProcessingUnit this, + picoos_uint16 *lf0Index, picoos_uint8 nI, picoos_single *phonF0) +{ + pam_subobj_t *pam; + picoos_uint8 *lfItem, numstreams; + picoos_uint16 lf0IndexOffset, sTemp; + picoos_single lfum, lfivar, lfz; + + pam = (pam_subobj_t *) this->subObj; + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + lf0IndexOffset = lf0Index[nI]; + + /*make the index 0 based*/ + if (lf0IndexOffset > 0) + lf0IndexOffset--; + + lf0IndexOffset += pam->pdflfz->stateoffset[nI]; + if (lf0IndexOffset > pam->pdflfz->numframes - 1) { + PICODBG_ERROR(("PAM flfzPdf access error, index overflow -> index: %d , numframes: %d", lf0Index, pam->pdflfz->numframes)); + return PICO_ERR_OTHER; + } + /* base pointer */ + lf0IndexOffset *= pam->pdflfz->vecsize; + + lfItem = &(pam->pdflfz->content[lf0IndexOffset]); + sTemp = (picoos_uint16) (((lfItem[1] << 8)) | lfItem[0]); + + lfum = (picoos_single) (sTemp << (pam->pdflfz->meanpowUm[0])); + numstreams = 3; + lfivar = (picoos_single) (((picoos_uint16) lfItem[numstreams * 2]) + << pam->pdflfz->ivarpow[0]); + lfz = (picoos_single) lfum / (picoos_single) lfivar; + lfz = (picoos_single) exp((double) lfz); + phonF0[nI] = (picoos_single) lfz; + + /*pitch modoification*/ + phonF0[nI] *= pam->pMod; + return PICO_OK; +}/*pam_get_f0*/ + +/** + * elementary rounding function + * @param fIn : (real) input value + * @return the rounded value + * @callgraph + * @callergraph + */ +static picoos_single f_round(picoos_single fIn) +{ + picoos_int32 iVal; + picoos_single fVal; + + iVal = (picoos_int32) fIn; + fVal = (picoos_single) iVal; + + if (fIn > (picoos_single) 0.0f) { + if ((fIn - fVal) < (picoos_single) 0.5f) + return fVal; + else + return fVal + (picoos_single) 1.0f; + } else { + if ((fVal - fIn) < (picoos_single) 0.5f) + return fVal; + else + return fVal - (picoos_single) 1.0f; + } +}/*f_round*/ + +/** + * updates the input vector for PAM + * @param this : Pam object pointer + * @return PICO_OK : update successful + * @return PICO_ERR_OTHER : errors on retrieving the PU pointer + * @remarks Modifies pam->sPhFeats[] + * @callgraph + * @callergraph + */ +static pico_status_t pam_update_vector(register picodata_ProcessingUnit this) +{ + pam_subobj_t *pam; + picoos_uint8 numstates, nI; + picoos_single fDur, f0avg, f0quant, minf0, maxf0, durquant1, durquant2, + mindur, maxdur1, maxdur2; + + pam = (pam_subobj_t *) this->subObj; + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + /*default init*/ + pam->sPhFeats[DUR] = 0; + pam->sPhFeats[F0] = 0; + /* + Hard coded parameters for quantization + */ + numstates = PICOPAM_NRSTPF; + f0quant = 30.0f; + minf0 = 90.0f; + maxf0 = 360.0f; + + durquant1 = 20.0f; + durquant2 = 100.0f; + mindur = 40.0f; + maxdur1 = 160.0f; + maxdur2 = 600.0f; + f0avg = 0.0f; + for (nI = 0; nI < numstates; nI++) + f0avg += pam->phonF0[nI]; + f0avg /= (picoos_single) numstates; + + f0avg = f_round(f0avg / f0quant) * f0quant; + if (f0avg < minf0) + f0avg = minf0; + if (f0avg > maxf0) + f0avg = maxf0; + + /*make initial silence of sentence shorter (see also pam_put_item)*/ + if ((pam->nCurrSyllable == 0) && (pam->nSyllPhoneme == 0)) { + pam->phonDur = 2 * 4; + } + + fDur = (picoos_single) pam->phonDur; + fDur = f_round(fDur / durquant1) * durquant1; + if (fDur < mindur) + fDur = mindur; + if (fDur > maxdur1) { + fDur = f_round(fDur / durquant2) * durquant2; + if (fDur > maxdur2) + fDur = maxdur2; + } + pam->sPhFeats[DUR] = (picoos_uint8) (fDur / (picoos_single) 10.0f); + pam->sPhFeats[F0] = (picoos_uint8) (f0avg / (picoos_single) 10.0f); + + return PICO_OK; +}/*pam_update_vector*/ + +/** + * compress a single feature in the range 0..9 + * @param inVal : the value to be compressed + * @return compVal : the compressed value + * @callgraph + * @callergraph + */ +static picoos_uint8 pamCompressComponent(picoos_uint8 inVal) +{ + if (inVal <= 5) + return inVal; + if ((5 < inVal) && (inVal <= 10)) + return 6; + if ((10 < inVal) && (inVal <= 20)) + return 7; + if ((20 < inVal) && (inVal <= 30)) + return 8; + return 9; +}/*pamCompressComponent*/ + +/** + * prepares the input vector for tree feeding + * @param this : Pam object pointer + * @return PICO_OK : vector expanded + * @return PICO_ERR_OTHER : errors on expansion or retrieving the PU pointer + * @remarks Modifies pam->sPhFeats[] + * @callgraph + * @callergraph + */ +static pico_status_t pam_expand_vector(register picodata_ProcessingUnit this) +{ + pam_subobj_t *pam; + picoos_uint8 *inVect, *phonVect, *outVect, nI; + picoos_int16 nOffs, nOffs1, nLen; + pam = (pam_subobj_t *) this->subObj; + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + inVect = &(pam->sSyllFeats[pam->nCurrSyllable].phoneV[0]); + phonVect = &(pam->sPhIds[0]); + outVect = &(pam->sPhFeats[0]); + /*just copy back*/ + for (nI = 0; nI < PICOPAM_INVEC_SIZE; nI++) + outVect[nI] = inVect[nI]; + /*now fill missing fields*/ + picoos_mem_copy((void*) &(inVect[FID]), &nOffs, sizeof(nOffs)); + /*offset to first phone of current syllable*/ + nOffs = nOffs + pam->nSyllPhoneme; /*offset to current phone of current syllable*/ + nLen = inVect[B3]; /*len of current syllable*/ + if (pam->nSyllPhoneme >= nLen) { + /*error on addressing current phone*/ + return PICO_ERR_OTHER; + } + /*previous of the previous phone*/ + nOffs1 = nOffs - 2; + if (nOffs1 >= 0) + outVect[P1] = phonVect[nOffs1]; + else + outVect[P1] = PICOPAM_PH_DONT_CARE_VAL; + /*previous phone*/ + nOffs1 = nOffs - 1; + if (nOffs1 >= 0) + outVect[P2] = phonVect[nOffs1]; + else + outVect[P2] = PICOPAM_PH_DONT_CARE_VAL; + /*^current phone*/ + outVect[P3] = phonVect[nOffs]; + + /*next phone*/ + nOffs1 = nOffs + 1; + if (nOffs1 < pam->nTotalPhonemes) + outVect[P4] = phonVect[nOffs1]; + else + outVect[P4] = PICOPAM_PH_DONT_CARE_VAL; + /*next of the next phone*/ + nOffs1 = nOffs + 2; + if (nOffs1 < pam->nTotalPhonemes) + outVect[P5] = phonVect[nOffs1]; + else + outVect[P5] = PICOPAM_PH_DONT_CARE_VAL; + /*pos of curr phone with respect to left syllable boundary*/ + outVect[P6] = pam->nSyllPhoneme + 1; + /*pos of curr phone with respect to right syllable boundary*/ + outVect[P7] = nLen - pam->nSyllPhoneme; + /*is current phone in consonant syllable boundary? (1:yes)*/ + if (pam->nSyllPhoneme < inVect[P8]) + outVect[P8] = 1; + else + outVect[P8] = 0; + return PICO_OK; +}/*pam_expand_vector*/ + +/** + * compresses the input vector for PAM + * @param this : Pam object pointer + * @return PICO_OK : compression successful + * @return PICO_ERR_OTHER : errors on retrieving the PU pointer + * @remarks Modifies pam->sPhFeats[] + * @callgraph + * @callergraph + */ +static pico_status_t pamCompressVector(register picodata_ProcessingUnit this) +{ + pam_subobj_t *pam; + picoos_uint8 *outVect, nI; + pam = (pam_subobj_t *) this->subObj; + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + outVect = &(pam->sPhFeats[0]); + for (nI = 0; nI < PICOPAM_INVEC_SIZE; nI++) { + switch (nI) { + case P1: + case P2: + case P3: + case P4: + case P5: + case B1: + case B2: + case B16: + case E1: + case H5: + /*don't do any compression*/ + break; + default: + /*do compression*/ + if (outVect[nI] != PICOPAM_DONT_CARE_VALUE) + outVect[nI] = pamCompressComponent(outVect[nI]); + else + outVect[nI] = PICOPAM_DONT_CARE_VAL; + break; + } + } + return PICO_OK; +}/*pamCompressVector*/ + +/** + * reorganizes the input vector for PAM + * @param this : Pam object pointer + * @return PICO_OK : reorganization successful + * @return PICO_ERR_OTHER : errors on retrieving the PU pointer + * @remarks Modifies pam->sPhFeats[] + * @callgraph + * @callergraph + */ +static pico_status_t pamReorgVector(register picodata_ProcessingUnit this) +{ + pam_subobj_t *pam; + picoos_uint8 *outVect, inVect[60], nI; + pam = (pam_subobj_t *) this->subObj; + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + outVect = &(pam->sPhFeats[0]); + for (nI = 0; nI < PICOPAM_INVEC_SIZE; nI++) inVect[nI] = outVect[nI]; + /*reorganize*/ + for (nI = T_B1; nI <= T_H5; nI++) { + switch (nI) { + case T_B1: + outVect[T_B1] = inVect[B1]; + break; + case T_B2: + outVect[T_B2] = inVect[B2]; + break; + case T_B3: + outVect[T_B3] = inVect[B3]; + break; + case T_B4: + outVect[T_B4] = inVect[B4]; + break; + case T_B5: + outVect[T_B5] = inVect[B5]; + break; + case T_B6: + outVect[T_B6] = inVect[B6]; + break; + case T_B7: + outVect[T_B7] = inVect[B7]; + break; + case T_B8: + outVect[T_B8] = inVect[B8]; + break; + case T_B9: + outVect[T_B9] = inVect[B9]; + break; + case T_B10: + outVect[T_B10] = inVect[B10]; + break; + case T_B11: + outVect[T_B11] = inVect[B11]; + break; + case T_B12: + outVect[T_B12] = inVect[B12]; + break; + case T_B13: + outVect[T_B13] = inVect[B13]; + break; + case T_B14: + outVect[T_B14] = inVect[B14]; + break; + case T_B15: + outVect[T_B15] = inVect[B15]; + break; + case T_B16: + outVect[T_B16] = inVect[B16]; + break; + case T_B17: + outVect[T_B17] = inVect[B17]; + break; + case T_B18: + outVect[T_B18] = inVect[B18]; + break; + case T_B19: + outVect[T_B19] = inVect[B19]; + break; + case T_B20: + outVect[T_B20] = inVect[B20]; + break; + case T_B21: + outVect[T_B21] = inVect[B21]; + break; + + case T_E1: + outVect[T_E1] = inVect[E1]; + break; + case T_E2: + outVect[T_E2] = inVect[E2]; + break; + case T_E3: + outVect[T_E3] = inVect[E3]; + break; + case T_E4: + outVect[T_E4] = inVect[E4]; + break; + case T_E5: + outVect[T_E5] = inVect[E5]; + break; + case T_E6: + outVect[T_E6] = inVect[E6]; + break; + case T_E7: + outVect[T_E7] = inVect[E7]; + break; + case T_E8: + outVect[T_E8] = inVect[E8]; + break; + case T_E9: + outVect[T_E9] = inVect[E9]; + break; + case T_E10: + outVect[T_E10] = inVect[E10]; + break; + case T_E11: + outVect[T_E11] = inVect[E11]; + break; + case T_E12: + outVect[T_E12] = inVect[E12]; + break; + case T_E13: + outVect[T_E13] = inVect[E13]; + break; + + case T_A3: + outVect[T_A3] = inVect[A3]; + break; + case T_C3: + outVect[T_C3] = inVect[C3]; + break; + case T_D2: + outVect[T_D2] = inVect[D2]; + break; + case T_F2: + outVect[T_F2] = inVect[F2]; + break; + + case T_G1: + outVect[T_G1] = inVect[G1]; + break; + case T_I1: + outVect[T_I1] = inVect[I1]; + break; + + case T_G2: + outVect[T_G2] = inVect[G2]; + break; + case T_I2: + outVect[T_I2] = inVect[I2]; + break; + + case T_H1: + outVect[T_H1] = inVect[H1]; + break; + case T_H2: + outVect[T_H2] = inVect[H2]; + break; + case T_H3: + outVect[T_H3] = inVect[H3]; + break; + case T_H4: + outVect[T_H4] = inVect[H4]; + break; + case T_H5: + outVect[T_H5] = inVect[H5]; + break; + } + } + return PICO_OK; +}/*pamReorgVector*/ + +/** + * puts a PAM item into PU output buffer + * @param this : Pam object pointer + * @param outBuff : output buffer base pointer + * @param outWritePos : offset in output buffer + * @param *bytesWr : actual bytes written + * @return PICO_OK : put successful + * @return PICO_ERR_OTHER : errors on retrieving the PU pointer + * @callgraph + * @callergraph + */ +static pico_status_t pam_put_item(register picodata_ProcessingUnit this, + picoos_uint8 *outBuff, picoos_uint16 outWritePos, picoos_uint8 *bytesWr) +{ + pam_subobj_t *pam; + picoos_uint8 *sDest, nI, nType, nIdx, fde; + picoos_uint32 pos, pos32; + picoos_int16 ft, dt; + picoos_uint16 uMinDur, uMaxDur; + pam = (pam_subobj_t *) this->subObj; + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + sDest = &(outBuff[outWritePos]); + sDest[0] = PICODATA_ITEM_PHONE; /*Item type*/ + sDest[1] = pam->sPhFeats[P3]; /*phonetic id*/ + sDest[2] = PICOPAM_NRSTPF; /*number of states per phone*/ + sDest[3] = sizeof(picoos_uint16) * PICOPAM_NRSTPF * 3; /*size of the item*/ + pos = 4; + /*make initial silence of sentence shorter (see also UpdateVector)*/ + if ((pam->nCurrSyllable == 0) && (pam->nSyllPhoneme == 0)) { + for (nI = 0; nI < PICOPAM_NRSTPF - 1; nI++) + pam->numFramesState[nI] = 0; + pam->numFramesState[nI] = 2; + } else { + /*manage silence syllables with prescribed durations*/ + pos32 = Min; + picoos_read_mem_pi_uint16(pam->sSyllFeats[pam->nCurrSyllable].phoneV, + &pos32, &uMinDur); + pos32 = Max; + picoos_read_mem_pi_uint16(pam->sSyllFeats[pam->nCurrSyllable].phoneV, + &pos32, &uMaxDur); + + if (uMaxDur > 0) { + /* Select weights*/ + nType = pam->sSyllFeats[pam->nCurrSyllable].phoneV[bnd]; + switch (nType) { + case PICODATA_ITEMINFO1_BOUND_SBEG: + nIdx = PICOPAM_PWIDX_SBEG; + break; + case PICODATA_ITEMINFO1_BOUND_PHR1: + nIdx = PICOPAM_PWIDX_PHR1; + break; + case PICODATA_ITEMINFO1_BOUND_PHR2: + nIdx = PICOPAM_PWIDX_PHR2; + break; + case PICODATA_ITEMINFO1_BOUND_SEND: + case PICODATA_ITEMINFO1_BOUND_TERM: + nIdx = PICOPAM_PWIDX_SEND; + break; + default: + nIdx = PICOPAM_PWIDX_DEFA; + break; + } + fde = 2; + ft = 0; + dt = 0; + picodata_transformDurations( + fde, /* 2's exponent of frame duration in ms, e.g. 2 for 4ms, 3 for 8ms */ + PICOPAM_NRSTPF, /* number of states per phone */ + &(pam->numFramesState[0]), /* estimated durations */ + pam->sil_weights[nIdx], /* integer weights */ + uMinDur, /* minimum target duration in ms */ + uMaxDur, /* maximum target duration in ms */ + ft, /* factor to be multiplied to get the target */ + &dt /* in/out, rest in ms */ + ); + } + } + /*put data*/ + for (nI = 0; nI < PICOPAM_NRSTPF; nI++) { + picoos_write_mem_pi_uint16(sDest, &pos, + (picoos_uint16) pam->numFramesState[nI]); + picoos_write_mem_pi_uint16(sDest, &pos, + (picoos_uint16) pam->lf0Index[nI]); + picoos_write_mem_pi_uint16(sDest, &pos, + (picoos_uint16) pam->mgcIndex[nI]); + } + *bytesWr = sizeof(picodata_itemhead_t) + sizeof(picoos_uint16) + * PICOPAM_NRSTPF * 3; + return PICO_OK; +}/*pam_put_item*/ + +/** + * puts a non PAM (queued) item into PU output buffer + * @param qItem : pointer to item to put + * @param outBuff : output buffer base pointer + * @param outWritePos : offset in output buffer + * @param *bytesWr : actual bytes written + * @return PICO_OK : put successful + * @return PICO_ERR_OTHER : errors on retrieving the PU pointer + * @callgraph + * @callergraph + */ +static pico_status_t pam_put_qItem(picoos_uint8 *qItem, picoos_uint8 *outBuff, + picoos_uint16 outWritePos, picoos_uint8 *bytesWr) +{ + picoos_uint8 *sDest, nI; + sDest = &(outBuff[outWritePos]); + *bytesWr = sizeof(picodata_itemhead_t); + for (nI = 0; nI < (sizeof(picodata_itemhead_t) + qItem[3]); nI++) { + sDest[nI] = qItem[nI]; + } + *bytesWr = nI; + return PICO_OK; +}/*pam_put_qItem*/ + +/** + * tells if an item is a PAM command (except play) + * @param qItem : input item to test + * @return TRUE : qItem is a PAM command (except play) + * @return FALSE : qItem not a PAM command + * @callgraph + * @callergraph + */ +static pico_status_t is_pam_command(const picoos_uint8 * qItem) +{ + switch (qItem[0]) { + + case PICODATA_ITEM_CMD: + switch (qItem[1]) { + case PICODATA_ITEMINFO1_CMD_FLUSH: + /* flush is for all PU's and as such it is also for PAM*/ + case PICODATA_ITEMINFO1_CMD_PITCH: + case PICODATA_ITEMINFO1_CMD_SPEED: + return TRUE; + break; + default: + break; + } + } + return FALSE; +}/*is_pam_command*/ + +/** + * tells if an item is a PAM PLAY command + * @param qItem : input item to test + * @return TRUE : qItem is a PAM PLAY command + * @return FALSE : qItem not a PAM PLAY command + * @callgraph + * @callergraph + */ +static pico_status_t is_pam_play_command(picoos_uint8 *qItem) +{ + switch (qItem[0]) { + + case PICODATA_ITEM_CMD: + switch (qItem[1]) { + case PICODATA_ITEMINFO1_CMD_PLAY: + if (qItem[2] == PICODATA_ITEMINFO2_CMD_TO_PAM) + return TRUE; + break; + default: + break; + } + } + return FALSE; +}/*is_pam_play_command*/ + +/** + * command processor for PAM pu + * @param this : Pam item subobject + * @param qItem : input item pointer + * @return PICOPAM_FLUSH_RECEIVED : when a FLUSH is received + * @return PICOPAM_CONTINUE : normal command processing + * @return PICODATA_PU_ERROR : errors in accessing data + * @callgraph + * @callergraph + */ +static pico_status_t pamDoCommand(register picodata_ProcessingUnit this, + picoos_uint8 *qItem) +{ + pam_subobj_t *pam; + picoos_single fValue; + picoos_uint16 nValue; + picoos_uint32 nPos; + pam = (pam_subobj_t *) this->subObj; + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + if (qItem[0] == PICODATA_ITEM_CMD) { + switch (qItem[1]) { + case PICODATA_ITEMINFO1_CMD_FLUSH: + /* flush is for all PU's and as such it is also for PAM : implement the flush!!*/ + pam_reset_processors(this); + pam->nLastAttachedItemId = pam->nCurrAttachedItem = 0; + pam->nAttachedItemsSize = 0; + return PICOPAM_FLUSH_RECEIVED; + break; + + case PICODATA_ITEMINFO1_CMD_PITCH: + case PICODATA_ITEMINFO1_CMD_SPEED: + nPos = 4; + picoos_read_mem_pi_uint16(qItem, &nPos, &nValue); + if (qItem[2] == 'a') { + /*absloute modifier*/ + fValue = (picoos_single) nValue / (picoos_single) 100.0f; + if (qItem[1] == PICODATA_ITEMINFO1_CMD_PITCH) + pam->pMod = fValue; + if (qItem[1] == PICODATA_ITEMINFO1_CMD_SPEED) + pam->dMod = (1.0f / fValue); + } + if (qItem[2] == 'r') { + /*relative modifier*/ + fValue = (picoos_single) nValue / (picoos_single) 1000.0f; + if (qItem[1] == PICODATA_ITEMINFO1_CMD_PITCH) + pam->pMod *= (1.0f / fValue); + if (qItem[1] == PICODATA_ITEMINFO1_CMD_SPEED) + pam->dMod *= (1.0f / fValue); + } + return PICOPAM_CONTINUE; + break; + + default: + break; + }/*end switch switch (qItem[1])*/ + }/*end if (qItem[0]==PICODATA_ITEM_CMD)*/ + return PICOPAM_CONTINUE; +}/*pamDoCommand*/ + +/** + * defines if an item has to be sent to following PUs + * @param qItem : input item pointer + * @return TRUE : item has to be transmitted to following PUs + * @return FALSE : item has to be consumed internallz on PAM + * @callgraph + * @callergraph + */ +static pico_status_t isItemToPut(picoos_uint8 *qItem) +{ + switch (qItem[0]) { + case PICODATA_ITEM_CMD: + /* is a command*/ + if (PICODATA_ITEMINFO1_CMD_SPEED == qItem[1]) { + /* SPEED consumed here*/ + return FALSE; + } + break; + case PICODATA_ITEM_BOUND: + switch (qItem[1]) { + case PICODATA_ITEMINFO1_BOUND_SBEG: + case PICODATA_ITEMINFO1_BOUND_PHR0: + case PICODATA_ITEMINFO1_BOUND_PHR1: + case PICODATA_ITEMINFO1_BOUND_PHR2: + case PICODATA_ITEMINFO1_BOUND_PHR3: + /*boudary items consumed here except SEND,TERM*/ + return FALSE; + break; + default: + break; + } + break; + default: + break; + } + /*all other items not explicitly mentioned here + are transmitted to next PUs*/ + return TRUE; +}/*isItemToPut*/ + +/** + * pushes a boundary TERM item into some buffer + * @param outBuff : output buffer base pointer + * @param outWritePos : offset in output buffer + * @param *bytesWr : actual bytes written + * @return PICO_OK + * @remarks used while forcing TERM input items in forward processing + * @callgraph + * @callergraph + */ +static pico_status_t pam_put_term(picoos_uint8 *outBuff, + picoos_uint16 outWritePos, picoos_uint8 *bytesWr) +{ + picoos_uint8 *sDest; + sDest = &(outBuff[outWritePos]); + sDest[0] = PICODATA_ITEM_BOUND; /*Item type*/ + sDest[1] = PICODATA_ITEMINFO1_BOUND_TERM; + sDest[2] = PICODATA_ITEMINFO2_BOUNDTYPE_T; + sDest[3] = 0; /*item size*/ + *bytesWr = 4; + return PICO_OK; +}/*pam_put_term*/ + +/** + * translates one full phone into a PHONE Item including DT Dur, F0 and CEP trees feature generation and traversal + * @param this : Pam item subobject pointer + * @return PICO_OK : processing successful + * @return PICODATA_PU_ERROR : error accessing PAM object + * @return !=PICO_OK : processing errors + * @callgraph + * @callergraph + */ +static pico_status_t pamPhoneProcess(register picodata_ProcessingUnit this) +{ + pam_subobj_t *pam; + pico_status_t sResult; + picokdt_classify_result_t dTreeResult; + picoos_uint8 nI, bWr; + + pam = (pam_subobj_t *) this->subObj; + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + /*expands current phone in current syllable in the corresponding vector pam->sPhFeats[]*/ + sResult = pam_expand_vector(this); + sResult = pamCompressVector(this); + sResult = pamReorgVector(this); + + /*tree traversal for duration*/ + if (!pam_do_tree(this, pam->dtdur, &(pam->sPhFeats[0]), PICOPAM_INVEC_SIZE, + &dTreeResult)) { + PICODBG_WARN(("problem using pam tree dtdur, using fallback value")); + dTreeResult.class = 0; + } + pam->durIndex = dTreeResult.class; + sResult = pam_get_duration(this, pam->durIndex, &(pam->phonDur), + &(pam->numFramesState[0])); + + /*tree traversal for pitch*/ + for (nI = 0; nI < PICOPAM_MAX_STATES_PER_PHONE; nI++) { + if (!pam_do_tree(this, pam->dtlfz[nI], &(pam->sPhFeats[0]), + PICOPAM_INVEC_SIZE, &dTreeResult)) { + PICODBG_WARN(("problem using pam tree lf0Tree, using fallback value")); + dTreeResult.class = 0; + } + pam->lf0Index[nI] = dTreeResult.class; + } + + /*pdf access for pitch*/ + for (nI = 0; nI < PICOPAM_MAX_STATES_PER_PHONE; nI++) { + sResult = pam_get_f0(this, &(pam->lf0Index[0]), nI, &(pam->phonF0[0])); + } + + /*update vector with duration and pitch for cep tree traversal*/ + sResult = pam_update_vector(this); + /*cep tree traversal*/ + for (nI = 0; nI < PICOPAM_MAX_STATES_PER_PHONE; nI++) { + + if (!pam_do_tree(this, pam->dtmgc[nI], &(pam->sPhFeats[0]), + PICOPAM_INVEC_SIZE, &dTreeResult)) { + PICODBG_WARN(("problem using pam tree lf0Tree, using fallback value")); + dTreeResult.class = 0; + } + pam->mgcIndex[nI] = dTreeResult.class; + } + /*put item to output buffer*/ + sResult = pam_put_item(this, pam->outBuf, pam->outWritePos, &bWr); + if (sResult == PICO_OK) + pam->outWritePos += bWr; + else + return sResult; + return PICO_OK; +}/*pamPhoneProcess*/ + +/** + * manages first syllable attached items when seen before SBEG + * @param this : Pam item subobject pointer + * @return PICO_OK (0) : default return code --> means no more items to be processed before 1st syllable + * @return PICOPAM_GOTO_FEED : go to feed state after this + * @return PICOPAM_GOTO_SCHEDULE : flush received + * @return PICODATA_PU_ERROR : errors + * @callgraph + * @callergraph + */ +static pico_status_t pamDoPreSyll(register picodata_ProcessingUnit this) +{ + pam_subobj_t *pam; + pico_status_t sResult; + picoos_uint8 bWr, nRc; + picoos_uint8 *qItem; + nRc = PICOPAM_PRE_SYLL_ENDED; + pam = (pam_subobj_t *) this->subObj; + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + /*regenerate initial items before the phonemes*/ + if (((qItem = pamPopAttachedSy0(this)) != NULL) && !((qItem[0] + == PICODATA_ITEM_BOUND) && (qItem[1] + == PICODATA_ITEMINFO1_BOUND_SBEG))) { + if (isItemToPut(qItem)) { + pam_put_qItem(qItem, pam->outBuf, pam->outWritePos, &bWr);/*popped item has to be sent to next PU*/ + pam->outWritePos += bWr; + nRc = PICOPAM_GOTO_FEED; + } + + if (is_pam_command(qItem) == TRUE) { + nRc = pamDoCommand(this, qItem); /*popped item is a PAM command : do it NOW!!*/ + if ((nRc == PICOPAM_FLUSH_RECEIVED) || (nRc == PICODATA_PU_ERROR)) { + /*FLUSH command RECEIVED or errors: stop ALL PROCESSING*/ + return nRc; + } + } + pam->nCurrAttachedItem++; + if (nRc == 0) + return PICOPAM_CONTINUE; + else + return nRc; + } + /*SBEG item management*/ + if ((qItem != NULL) && (qItem[0] == PICODATA_ITEM_BOUND) && (qItem[1] + == PICODATA_ITEMINFO1_BOUND_SBEG)) { + sResult = pam_put_qItem(qItem, pam->outBuf, pam->outWritePos, &bWr); + pam->outWritePos += bWr; + pam->nCurrAttachedItem++; + nRc = PICOPAM_GOTO_FEED; + } + return nRc; +}/*pamDoPreSyll*/ + +/** + * performs a step of the pam processing + * @param this : Pam item subobject pointer + * @param mode : mode for the PU + * @param *numBytesOutput : pointer to output number fo bytes produced + * @return PICODATA_PU_IDLE : nothing to do + * @return PICODATA_PU_BUSY : still tasks undergoing + * @return PICODATA_PU_ERROR : errors on processing + * @callgraph + * @callergraph + */ +static picodata_step_result_t pam_step(register picodata_ProcessingUnit this, + picoos_int16 mode, picoos_uint16 * numBytesOutput) +{ + + register pam_subobj_t * pam; + + pico_status_t sResult; + picoos_uint16 blen, numinb, numoutb; + pico_status_t rv; + picoos_uint8 bWr; + picoos_uint8 bForcedItem[4]; + picoos_uint8 *qItem; + + numinb = 0; + numoutb = 0; + rv = PICO_OK; + + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + pam = (pam_subobj_t *) this->subObj; + mode = mode; /* avoid warning "var not used in this function"*/ + /*Init number of output bytes*/ + *numBytesOutput = 0; + + while (1) { /* exit via return */ + + PICODBG_DEBUG(("pam_step -- doing state %i",pam->procState)); + + switch (pam->procState) { + + case PICOPAM_COLLECT: + /* *************** item collector ***********************************/ + /*collecting items from the PU input buffer*/ + sResult = picodata_cbGetItem(this->cbIn, + &(pam->inBuf[pam->inWritePos]), pam->inBufSize + - pam->inWritePos, &blen); + if (sResult != PICO_OK) { + if (sResult == PICO_EOF) { + /*no items available : remain in state 0 and return idle*/ + return PICODATA_PU_IDLE; + } else { + /*errors : remain in state 0 and return error*/ + PICODBG_DEBUG(("pam_step(PICOPAM_COLLECT) -- Errors on item buffer input, status: %d",sResult)); + return PICODATA_PU_ERROR; + } + } + + PICODBG_DEBUG(("pam_step -- got item, status: %d",sResult)); + sResult = picodata_is_valid_item( + &(pam->inBuf[pam->inWritePos]), blen); + if (sResult != TRUE) { + /*input item is not valid : consume the input item and stay in COLLECT*/ + pam->inWritePos += blen; + pam->inReadPos += blen; + if (pam->inReadPos >= pam->inWritePos) { + pam->inReadPos = 0; + pam->inWritePos = 0; + }PICODBG_DEBUG(("pam_step -- item is not valid, type: %d",pam->inBuf[pam->inWritePos])); + return PICODATA_PU_BUSY; + } + + /*update input write pointer + move to "schedule" state*/ + pam->inWritePos += blen; + pam->procState = PICOPAM_SCHEDULE; + return PICODATA_PU_BUSY; + + case PICOPAM_SCHEDULE: + /* check out if more items are available */ + if (pam->inReadPos >= pam->inWritePos) { + /*no more items : back to collect state*/ + pam->procState = PICOPAM_COLLECT; + return PICODATA_PU_BUSY; + } + /* we have one full valid item, with len>0 starting at + pam->inBuf[pam->inReadPos]; here we decide how to elaborate it */ + + /* PLAY management */ + if (is_pam_play_command(&(pam->inBuf[pam->inReadPos])) == TRUE) { + /*consume the input item : it has been managed*/ + pam->inReadPos += pam->inBuf[pam->inReadPos + 3] + + sizeof(picodata_itemhead_t); + if (pam->inReadPos >= pam->inWritePos) { + pam->inReadPos = 0; + pam->inWritePos = 0; + } + /*stay in schedule*/ + return PICODATA_PU_BUSY; + } + + if (pam_check_immediate(this, &(pam->inBuf[pam->inReadPos]))) { + /* item has to be sent to next PU NOW : switch to "immediate" state */ + pam->procState = PICOPAM_IMMEDIATE; + return PICODATA_PU_BUSY; + } + if (pamCheckResourceLimits(this, &(pam->inBuf[pam->inReadPos]))) { + /* item would not fit into local buffers -->> free some space -->> + switch to "force term" state */ + pam->procState = PICOPAM_FORWARD_FORCE_TERM; + return PICODATA_PU_BUSY; + } + + if (pam_deal_with(&(pam->inBuf[pam->inReadPos]))) { + /* item has to be managed by the "forward" state : switch to forward state*/ + pam->procState = PICOPAM_FORWARD; + return PICODATA_PU_BUSY; + } + + if (pam_hastobe_queued(this, &(pam->inBuf[pam->inReadPos]))) { + /* item is not for PAM so it has to be queued internally */ + pam_queue(this, &(pam->inBuf[pam->inReadPos])); + /*consume the input item : it has been queued*/ + pam->inReadPos += pam->inBuf[pam->inReadPos + 3] + + sizeof(picodata_itemhead_t); + if (pam->inReadPos >= pam->inWritePos) { + pam->inReadPos = 0; + pam->inWritePos = 0; + } + return PICODATA_PU_BUSY; + } + /*if we get here something wrong happened. Being the the item valid, + switch to "immediate" state -> send it to next PU -> */ + PICODBG_DEBUG(("pam_step (PICOPAM_SCHEDULE) -- unexpected item is sent to next PU !!")); + pam->procState = PICOPAM_IMMEDIATE; + return PICODATA_PU_BUSY; + break; /*PICOPAM_SCHEDULE*/ + + case PICOPAM_FORWARD: + /*we have one full valid item, with len>0 starting at pam->inBuf[pam->inReadPos]. + furthermore this item should be in the set {BOUND,SYLL}. + No other items should arrive here*/ + sResult = pam_adapter_forward_step(this, + &(pam->inBuf[pam->inReadPos])); + /*decide if this item has to be queued for later re-synchronization + normally this is only done for SEND/TERM items*/ + if (pam_hastobe_queued(this, &(pam->inBuf[pam->inReadPos]))) { + /*item has to be queued iternally in local storage*/ + pam_queue(this, &(pam->inBuf[pam->inReadPos])); + } + /*now assign next state according to Forward results*/ + switch (sResult) { + case PICOPAM_READY: + pam->needMoreInput = FALSE; + /*consume the input item : it has already been stored*/ + pam->inReadPos += pam->inBuf[pam->inReadPos + 3] + + sizeof(picodata_itemhead_t); + if (pam->inReadPos >= pam->inWritePos) { + pam->inReadPos = 0; + pam->inWritePos = 0; + } + /*activate backward processing*/ + sResult = pam_adapter_backward_step(this); + if (sResult == PICO_OK) { + pam->procState = PICOPAM_PROCESS; + return PICODATA_PU_BUSY; + } else { + PICODBG_DEBUG(("pam_step (PICOPAM_FORWARD) -- wrong return from BackwardStep: %d -- Buffered sentence will be discarded",sResult)); + pam_reset_processors(this); + pam->nLastAttachedItemId = pam->nCurrAttachedItem + = 0; + pam->nAttachedItemsSize = 0; + + pam->procState = PICOPAM_SCHEDULE; + return PICODATA_PU_BUSY; + } + break; + + case PICOPAM_MORE: + pam->needMoreInput = TRUE; + /*consume the input item : it has already been stored*/ + pam->inReadPos += pam->inBuf[pam->inReadPos + 3] + + sizeof(picodata_itemhead_t); + if (pam->inReadPos >= pam->inWritePos) { + /*input is finished and PAM need more data : + clenaup input buffer + switch state back to "schedule state" + */ + pam->inReadPos = 0; + pam->inWritePos = 0; + pam->procState = PICOPAM_SCHEDULE; + return PICODATA_PU_ATOMIC; + } else { + /*input is not finished and need more data : + remain in state "PICOPAM_FORWARD" */ + return PICODATA_PU_ATOMIC; + } + break; + + case PICOPAM_NA: + default: + /*this item has not been stored in internal buffers: + assign this item to the management of + "immediate" state*/ + pam->procState = PICOPAM_IMMEDIATE; + return PICODATA_PU_BUSY; + break; + } /*end switch sResult*/ + break; /*PICOPAM_FORWARD*/ + + case PICOPAM_FORWARD_FORCE_TERM: + /*we have one full valid item, with len>0 + starting at pam->inBuf[pam->inReadPos] but we decided + to force a TERM item before, without losing the item in + inBuf[inReadPos] : --> generate a TERM item and do the + forward processing */ + pam_put_term(bForcedItem, 0, &bWr); + sResult = pam_adapter_forward_step(this, &(bForcedItem[0])); + switch (sResult) { + case PICOPAM_READY: + pam_queue(this, &(bForcedItem[0])); + /*activate backward processing*/ + sResult = pam_adapter_backward_step(this); + if (sResult == PICO_OK) { + pam->procState = PICOPAM_PROCESS; + return PICODATA_PU_BUSY; + } else { + PICODBG_DEBUG(("pam_step (PICOPAM_FORWARD_FORCE_TERM) -- wrong return from BackwardStep: %d -- Buffered sentence will be discarded",sResult)); + pam_reset_processors(this); + pam->nLastAttachedItemId = pam->nCurrAttachedItem + = 0; + pam->nAttachedItemsSize = 0; + + pam->procState = PICOPAM_SCHEDULE; + return PICODATA_PU_BUSY; + } + break; + + default: + PICODBG_DEBUG(("pam_step (PICOPAM_FORWARD_FORCE_TERM) -- Forced a TERM but processing do not appear to end -- Buffered sentence will be discarded",sResult)); + pam_reset_processors(this); + pam->nLastAttachedItemId = pam->nCurrAttachedItem = 0; + pam->nAttachedItemsSize = 0; + + pam->procState = PICOPAM_SCHEDULE; + return PICODATA_PU_BUSY; + break; + + } /*end switch sResult*/ + break; /*PICOPAM_FORWARD_FORCE_TERM*/ + + case PICOPAM_PROCESS: + + if ((PICOPAM_FRAME_ITEM_SIZE + 4) > (pam->outBufSize + - pam->outWritePos)) { + /*WARNING (buffer overflow): leave status unchanged until output buffer free */ + return PICODATA_PU_BUSY; + } + + if (pam->nCurrSyllable == 0) { + sResult = pamDoPreSyll(this); + if (sResult == PICOPAM_GOTO_FEED) { + /* + items pushed to output buffer : + switch to "feed" but then back + to "process" + */ + pam->retState = PICOPAM_PROCESS; + pam->procState = PICOPAM_FEED; + return PICODATA_PU_BUSY; + } + if (sResult == PICOPAM_CONTINUE) { + /* + items processed (maybe commands) : + return (maybe we need to process other + items in pre_syll) and then back to "process" + */ + pam->retState = PICOPAM_PROCESS; + pam->procState = PICOPAM_PROCESS; + return PICODATA_PU_BUSY; + } + + if ((sResult == PICOPAM_FLUSH_RECEIVED) || (sResult + == PICODATA_PU_ERROR)) { + /* + items processed were a flush or + problems found: switch to "schedule" + and abort all processing + */ + pam->retState = PICOPAM_SCHEDULE; + pam->procState = PICOPAM_SCHEDULE; + return PICODATA_PU_BUSY; + } + if (sResult == PICOPAM_PRE_SYLL_ENDED) { + /* + we get here when pam->nCurrSyllable==0 and + no more items to be processed before the syllable + */ + sResult = sResult; + } + } + + if (pamHasToProcess(this)) { + if (pamPhoneProcess(this) == PICO_OK) { + sResult = pamUpdateProcess(this); + pam->procState = PICOPAM_FEED; /*switch to feed*/ + return PICODATA_PU_BUSY; + } else { + PICODBG_DEBUG(("pam_step(PICOPAM_PROCESS) --- NULL return from pamPhoneProcess")); + return PICODATA_PU_ERROR; + } + } + + if (pamHasToPop(this) != FALSE) { + if ((qItem = pamPopItem(this)) == NULL) { + PICODBG_DEBUG(("pam_step(PICOPAM_PROCESS) --- NULL return from pamPopItem")); + return PICODATA_PU_ERROR; + } + + if (isItemToPut(qItem)) { + /*popped item has to be sent to next PU*/ + sResult = pam_put_qItem(qItem, pam->outBuf, + pam->outWritePos, &bWr); + if (sResult != PICO_OK) { + PICODBG_DEBUG(("pam_step(PICOPAM_PROCESS) --- Error on writing item to output buffer")); + return PICODATA_PU_ERROR; + } + pam->outWritePos += bWr; /*item write ok*/ + pam->procState = PICOPAM_FEED; /*switch to feed*/ + } + + /*moved command processing here (after pam_put_qItem) because of FLUSH command could erase + * the syllable structure and make it impossible to transmit the flush to other PUs*/ + if (is_pam_command(qItem) == TRUE) { + sResult = pamDoCommand(this, qItem); /*popped item is a PAM command : do it NOW!!*/ + if ((sResult == PICOPAM_FLUSH_RECEIVED) || (sResult + == PICODATA_PU_ERROR)) { + pam->retState = PICOPAM_SCHEDULE; + pam->procState = PICOPAM_SCHEDULE; /*switch to schedule */ + return PICODATA_PU_BUSY; + } + } + /*update PAM status: if more items attached to the current syllable + stay in current syllable, otherwise move to next syllable and switch + to processing phones */ + sResult = pamUpdateProcess(this); /*both "doCommand" or "put" : update PAM status*/ + return PICODATA_PU_BUSY; + } else { + pam->procState = PICOPAM_SCHEDULE; /*switch to schedule */ + return PICODATA_PU_BUSY; + } + + break; /*PICOPAM_PROCESS*/ + + case PICOPAM_IMMEDIATE: + /* *** item is output NOW!!! */ + /*context: full valid item, with len> starting at pam->inBuf[pam->inReadPos]*/ + numinb = PICODATA_ITEM_HEADSIZE + + pam->inBuf[pam->inReadPos + 3]; + sResult = picodata_copy_item(&(pam->inBuf[pam->inReadPos]), + numinb, &(pam->outBuf[pam->outWritePos]), + pam->outBufSize - pam->outWritePos, &numoutb); + + if (sResult == PICO_OK) { + pam->inReadPos += numinb; + if (pam->inReadPos >= pam->inWritePos) { + pam->inReadPos = 0; + pam->inWritePos = 0; + pam->needMoreInput = FALSE; + } + pam->outWritePos += numoutb; + pam->procState = PICOPAM_FEED; /*switch to FEED state*/ + pam->retState = PICOPAM_SCHEDULE; /*back to SCHEDULE after FEED*/ + } else { + /* + PICO_EXC_BUF_IGNORE + PICO_EXC_BUF_UNDERFLOW + PICO_EXC_BUF_OVERFLOW + */ + PICODBG_DEBUG(("pam_step(PICOPAM_IMMEDIATE) --- wrong return from picodata_copy_item:%d",sResult)); + return PICODATA_PU_ERROR; + } + return PICODATA_PU_BUSY; + break; /*PICOPAM_IMMEDIATE*/ + + case PICOPAM_FEED: + /* *************** item output/feeding ***********************************/ + /*feeding items to PU output buffer*/ + sResult = picodata_cbPutItem(this->cbOut, + &(pam->outBuf[pam->outReadPos]), pam->outWritePos + - pam->outReadPos, &numoutb); + PICODBG_DEBUG(("pam_step -- put item, status: %d",sResult)); + if (PICO_OK == sResult) { + + PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG], + (picoos_uint8 *)"pam: ", + pam->outBuf + pam->outReadPos, pam->outBufSize); + + pam->outReadPos += numoutb; + *numBytesOutput = numoutb; + if (pam->outReadPos >= pam->outWritePos) { + /*reset the output pointers*/ + pam->outReadPos = 0; + pam->outWritePos = 0; + /*switch to appropriate state*/ + switch (pam->retState) { + case PICOPAM_IMMEDIATE: + pam->procState = PICOPAM_IMMEDIATE; + pam->retState = PICOPAM_SCHEDULE; + return PICODATA_PU_BUSY; + break; + case PICOPAM_PLAY: + pam->procState = PICOPAM_PLAY; + pam->retState = PICOPAM_SCHEDULE; + return PICODATA_PU_BUSY; + break; + default: + break; + } + /*Define next state + a)process (if current sentence has more data to process) + b)schedule (no more data to process in current sentence) + NOTE : case b)also happens when dealing with non BOUND/SYLL items*/ + if ((pamHasToProcess(this)) || (pamHasToPop(this))) { + pam->procState = PICOPAM_PROCESS; + } else { + pam->nCurrSyllable = -1; + pam_reset_processors(this); + pam->nLastAttachedItemId = pam->nCurrAttachedItem + = 0; + pam->nAttachedItemsSize = 0; + + pam->nSyllPhoneme = 0; + pam->procState = PICOPAM_SCHEDULE; + } + } + return PICODATA_PU_BUSY; + + } else if (PICO_EXC_BUF_OVERFLOW == sResult) { + + PICODBG_DEBUG(("pam_step ** feeding, overflow, PICODATA_PU_OUT_FULL")); + return PICODATA_PU_OUT_FULL; + + } else if ((PICO_EXC_BUF_UNDERFLOW == sResult) + || (PICO_ERR_OTHER == sResult)) { + + PICODBG_DEBUG(("pam_step ** feeding problem, discarding item")); + pam->outReadPos = 0; + pam->outWritePos = 0; + pam->procState = PICOPAM_COLLECT; + return PICODATA_PU_ERROR; + + } + break; /*PICOPAM_FEED*/ + + default: + /*NOT feeding items*/ + sResult = PICO_EXC_BUF_IGNORE; + break; + }/*end switch*/ + return PICODATA_PU_BUSY; /*check if there is more data to process after feeding*/ + + }/*end while*/ + return PICODATA_PU_IDLE; +}/*pam_step*/ + +/** + * performs one step of a PamTree + * @param this : Pam item subobject pointer + * @param dtpam : the Pam decision tree + * @param *invec : the input vector pointer + * @param inveclen : length of the input vector + * @param *dtres : the classification result + * @return dtres->set : the result of tree traversal + * @callgraph + * @callergraph + */ +static picoos_uint8 pam_do_tree(register picodata_ProcessingUnit this, + const picokdt_DtPAM dtpam, const picoos_uint8 *invec, + const picoos_uint8 inveclen, picokdt_classify_result_t *dtres) +{ + picoos_uint8 okay; + + okay = TRUE; + /* construct input vector, which is set in dtpam */ + if (!picokdt_dtPAMconstructInVec(dtpam, invec, inveclen)) { + /* error constructing invec */ + PICODBG_WARN(("problem with invec")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_INVECTOR, NULL, NULL); + okay = FALSE; + } + /* classify */ + if (okay && (!picokdt_dtPAMclassify(dtpam))) { + /* error doing classification */ + PICODBG_WARN(("problem classifying")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_CLASSIFICATION, NULL, + NULL); + okay = FALSE; + } + /* decompose */ + if (okay && (!picokdt_dtPAMdecomposeOutClass(dtpam, dtres))) { + /* error decomposing */ + PICODBG_WARN(("problem decomposing")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_OUTVECTOR, NULL, NULL); + okay = FALSE; + } + + PICODBG_TRACE(("dtpam output class: %d", dtres->class)); + + return dtres->set; +}/*pam_do_tree*/ + +/** + * returns the carrier vowel id inside a syllable + * @param this : Pam item subobject pointer + * @param item : the full syllable item + * @param *pos : pointer to the variable to receive the position of the carrier vowel + * @return the phonetic id for the carrier vowel inside the syllable + * @callgraph + * @callergraph + */ +static picoos_uint8 pam_get_vowel_name(register picodata_ProcessingUnit this, + picoos_uint8 *item, picoos_uint8 *pos) +{ + pam_subobj_t *pam; + picoos_uint8 *phon, nI, nCond1; + if (NULL == this || NULL == this->subObj) { + return 0; + } + pam = (pam_subobj_t *) this->subObj; + + if (item == NULL) + return 0; + if (item[3] == 0) + return 0; + phon = &item[4]; + for (nI = 0; nI < item[3]; nI++) { + nCond1 = picoktab_isSyllCarrier(pam->tabphones, phon[nI]); + if (nCond1) { + *pos = nI; + return phon[nI]; + } + } + return 0; +}/*pam_get_vowel_name */ + +/** + * returns the pause phone id in the current ph.alphabet + * @param this : Pam sub object pointer + * @return the (numeric) phonetic id of the pause phone in current phonetic alphabet + * @return 0 : errors on getting the pam subobject pointer + * @callgraph + * @callergraph + */ +static picoos_uint8 pam_get_pause_id(register picodata_ProcessingUnit this) +{ + picoos_uint8 nVal1; + /*picoos_uint8 nVal2; */ + pam_subobj_t *pam; + if (NULL == this || NULL == this->subObj) { + return 0; + } + pam = (pam_subobj_t *) this->subObj; + nVal1 = picoktab_getPauseID(pam->tabphones); + return nVal1; +}/*pam_get_pause_id */ + +/** + * returns the pam sentence type (declarative, interrogative...) + * @param iteminfo1 : the boundary item info 1 + * @param iteminfo2 : the boundary item info 2 + * @return the sentence type suitably encoded for trees + * @callgraph + * @callergraph + */ +static picoos_uint8 pam_map_sentence_type(picoos_uint8 iteminfo1, + picoos_uint8 iteminfo2) +{ + switch (iteminfo2) { + case PICODATA_ITEMINFO2_BOUNDTYPE_P: + return PICOPAM_DECLARATIVE; + case PICODATA_ITEMINFO2_BOUNDTYPE_T: + return PICOPAM_DECLARATIVE; + case PICODATA_ITEMINFO2_BOUNDTYPE_Q: + return PICOPAM_INTERROGATIVE; + case PICODATA_ITEMINFO2_BOUNDTYPE_E: + return PICOPAM_DECLARATIVE; + default: + return PICOPAM_DECLARATIVE; + } + iteminfo1 = iteminfo1; /* avoid warning "var not used in this function"*/ + return PICOPAM_DECLARATIVE; +}/*pam_map_sentence_type */ + +/** + * returns the pam phrase type + * @param iteminfo1 : the boundary item info 1 + * @param iteminfo2 : the boundary item info 2 + * @return the phrase type suitably encoded for trees + * @callgraph + * @callergraph + */ +static picoos_uint8 pam_map_phrase_type(picoos_uint8 iteminfo1, + picoos_uint8 iteminfo2) +{ + + switch (iteminfo2) { + case PICODATA_ITEMINFO2_BOUNDTYPE_P: + switch (iteminfo1) { + case PICODATA_ITEMINFO1_BOUND_PHR1: +# ifdef PAM_PHR2_WITH_PR1 + case PICODATA_ITEMINFO1_BOUND_PHR2: +# endif + return PICOPAM_P; /*current_prhase type = "P" (encoded to 1) */ + break; + case PICODATA_ITEMINFO1_BOUND_PHR3: +# ifdef PAM_PHR2_WITH_PR3 + case PICODATA_ITEMINFO1_BOUND_PHR2 : +# endif + return PICOPAM_p; /*current_prhase type = "p" (encoded to 2) */ + break; + case PICODATA_ITEMINFO1_BOUND_SBEG: + return PICOPAM_P; /*current_prhase type = "P" (encoded to 1) */ + break; + default: + PICODBG_DEBUG(("Map pam_map_phrase_type : unexpected iteminfo1")); + return PICOPAM_P; /*current_prhase type = "P" (encoded to 1) */ + break; + } + case PICODATA_ITEMINFO2_BOUNDTYPE_T: + return PICOPAM_T; /*current_prhase type = "T" (encoded to 0) */ + break; + case PICODATA_ITEMINFO2_BOUNDTYPE_E: + return PICOPAM_T; /*current_prhase type = "T" (encoded to 0) */ + break; + case PICODATA_ITEMINFO2_BOUNDTYPE_Q: + return PICOPAM_Y; /*current_prhase type = "T" (encoded to 0) */ + break; + default: + PICODBG_DEBUG(("Map pam_map_phrase_type : unexpected iteminfo2")); + return PICOPAM_T; /*current_prhase type = "T" (encoded to 0) */ + break; + }PICODBG_DEBUG(("Map pam_map_phrase_type : unexpected iteminfo2")); + return PICOPAM_T; /*current_prhase type = "T" (encoded to 0) */ + +}/*pam_map_phrase_type */ + +/** + * does the cleanup of the sub object processors flags at sentence start + * @param this : pointer to PAM PU sub object pointer + * @return PICO_OK : reset OK + * @return PICO_ERR_OTHER : errors on getting pam sub obj pointer + * @callgraph + * @callergraph + */ +static pico_status_t pam_reset_processors(register picodata_ProcessingUnit this) +{ + pam_subobj_t *pam; + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + pam = (pam_subobj_t *) this->subObj; + + pam->nCurrSyllable = -1; + pam->nTotalPhonemes = pam->nSyllPhoneme = pam->nCurrPhoneme + = pam->nTotalSyllables = pam->sType = pam->pType = 0; + pam->dRest = 0.0f; + /*set all to 0*/ + pam->a3_overall_syllable = pam->a3_primary_phrase_syllable = pam->b4_b5_syllable = + pam->b6_b7_syllable = pam->b6_b7_state = pam->b8_b9_stressed_syllable = + pam->b10_b11_accented_syllable = pam->b12_b13_syllable = pam->b12_b13_state = + pam->b14_b15_syllable = pam->b14_b15_state = pam->b17_b19_syllable = + pam->b17_b19_state = pam->b18_b20_b21_syllable = pam->b18_b20_b21_state = + pam->c3_overall_syllable= pam->c3_primary_phrase_syllable = pam->d2_syllable_in_word = + pam->d2_prev_syllable_in_word = pam->d2_current_primary_phrase_word = pam->e1_syllable_word_start = + pam->e1_syllable_word_end= pam->e1_content = pam->e2_syllable_word_start = + pam->e2_syllable_word_end= pam->e3_e4_word = pam->e3_e4_state = + pam->e5_e6_content_word = pam->e5_e6_content = pam->e7_e8_word = + pam->e7_e8_content = pam->e7_e8_state = pam->e9_e11_word = + pam->e9_e11_saw_word = pam->e9_e11_state = pam->e10_e12_e13_word = + pam->e10_e12_e13_state = pam->e10_e12_e13_saw_word = pam->f2_overall_word = + pam->f2_word_syllable = pam->f2_next_word_syllable = pam->f2_current_primary_phrase_word = + pam->g1_current_secondary_phrase_syllable = pam->g1_current_syllable = + pam->g2_current_secondary_phrase_word = pam->g2_current_word = + pam->h1_current_secondary_phrase_syll = pam->h2_current_secondary_phrase_word = + pam->h3_h4_current_secondary_phrase_word = pam->h5_current_phrase_type = + pam->h5_syllable = pam->h5_state = pam->i1_secondary_phrase_syllable = + pam->i1_next_secondary_phrase_syllable = pam->i2_secondary_phrase_word = + pam->i2_next_secondary_phrase_word = pam->j1_utterance_syllable = + pam->j2_utterance_word = pam->j3_utterance_sec_phrases = 0; + /*Override 0 with 1*/ + pam->b4_b5_syllable = pam->b17_b19_syllable = pam->b18_b20_b21_syllable = + pam->e9_e11_word = pam->e10_e12_e13_word = pam->e7_e8_word = + pam->h2_current_secondary_phrase_word = 1; + /*Override 0 with -1*/ + pam->e1_syllable_word_start = pam->e1_syllable_word_end = pam->e2_syllable_word_start = + pam->e2_syllable_word_end = -1; + + return PICO_OK; +}/*pam_reset_processors*/ + +/** + * does the cleanup of the sub object processors flags before the backward step + * @param this : pointer to PAM PU sub object pointer + * @return PICO_OK : reset OK + * @return PICO_ERR_OTHER : errors on getting pam sub obj pointer + * @callgraph + * @callergraph + */ +static pico_status_t pam_reset_processors_back( + register picodata_ProcessingUnit this) +{ + pam_subobj_t *pam; + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + pam = (pam_subobj_t *) this->subObj; + + /*set all to 0*/ + pam->a3_overall_syllable + = pam->a3_primary_phrase_syllable + = pam->b4_b5_syllable + = pam->b6_b7_syllable + = pam->b6_b7_state + = pam->b8_b9_stressed_syllable + = pam->b10_b11_accented_syllable + = pam->b12_b13_syllable + = pam->b12_b13_state + = pam->b14_b15_syllable + = pam->b14_b15_state + = pam->b17_b19_syllable + = pam->b17_b19_state + = pam->b18_b20_b21_syllable + = pam->b18_b20_b21_state + = pam->c3_overall_syllable + = pam->c3_primary_phrase_syllable + = pam->d2_syllable_in_word + = pam->d2_prev_syllable_in_word + = pam->d2_current_primary_phrase_word + = pam->e1_syllable_word_start + = pam->e1_syllable_word_end + = pam->e1_content + = pam->e2_syllable_word_start + = pam->e2_syllable_word_end + = pam->e3_e4_word + = pam->e3_e4_state + = pam->e5_e6_content_word + = pam->e5_e6_content + = pam->e7_e8_word + = pam->e7_e8_content + = pam->e7_e8_state + = pam->e9_e11_word + = pam->e9_e11_saw_word + = pam->e9_e11_state + = pam->e10_e12_e13_word + = pam->e10_e12_e13_state + = pam->e10_e12_e13_saw_word + = pam->f2_overall_word + = pam->f2_word_syllable + = pam->f2_next_word_syllable + = pam->f2_current_primary_phrase_word + = pam->g1_current_secondary_phrase_syllable + = pam->g1_current_syllable + = pam->g2_current_secondary_phrase_word + = pam->g2_current_word + = pam->h1_current_secondary_phrase_syll + = pam->h2_current_secondary_phrase_word + = pam->h3_h4_current_secondary_phrase_word + = pam->h5_current_phrase_type + = pam->h5_state + = pam->i1_secondary_phrase_syllable + = pam->i1_next_secondary_phrase_syllable + = pam->i2_secondary_phrase_word + = pam->i2_next_secondary_phrase_word + = 0; + /*Override 0 with 1*/ + pam->b4_b5_syllable = pam->b17_b19_syllable = pam->b18_b20_b21_syllable + = pam->e9_e11_word = pam->e10_e12_e13_word = pam->e7_e8_word + = pam->h2_current_secondary_phrase_word = 1; + /*Override 0 with -1*/ + pam->e1_syllable_word_start = pam->e1_syllable_word_end + = pam->e2_syllable_word_start = pam->e2_syllable_word_end = -1; + + return PICO_OK; +}/*pam_reset_processors_back*/ + +/** + * processes an input event for a specific feature + * @param this : pointer to PAM PU sub object pointer + * @param nFeat : feature column to process + * @param event_type : event id among syll/boundprim/boundsec/boundword + * @param direction : forward(0)/backward(1) + * @return PICO_OK : process OK + * @return PICO_ERR_OTHER : errors on getting pam sub obj pointer + * @callgraph + * @callergraph + */ +static pico_status_t pam_process_event_feature( + register picodata_ProcessingUnit this, picoos_uint8 nFeat, + picoos_uint8 event_type, picoos_uint8 direction) +{ + picoos_uint8 sDest, nI; + picoos_uint16 syllCurr; + pam_subobj_t *pam; + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + pam = (pam_subobj_t *) this->subObj; + syllCurr = pam->nCurrSyllable; + switch (nFeat) { + case A3: + /*processor for A3*/ + switch (direction) { + case PICOPAM_DIR_FORW: + if (event_type == PICOPAM_EVENT_SYLL) { + if ((pam->sSyllFeats[pam->nCurrSyllable].phoneV[P1] + == 1) || (pam->a3_primary_phrase_syllable >= 1)) { + if (pam->a3_overall_syllable < 1) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[A3] + = 0; + else + pam->sSyllFeats[pam->nCurrSyllable].phoneV[A3] + = pam->sSyllFeats[pam->nCurrSyllable + - 1].phoneV[B3]; + } else { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[A3] = 0; + } + pam->a3_primary_phrase_syllable++; + pam->a3_overall_syllable++; + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->a3_primary_phrase_syllable = 0; + } + break; + case PICOPAM_DIR_BACK: + /*do nothing*/ + break; + } + break; + case B1: + case B2: + case B3: + /*done in createSyllable*/ + break; + case B4:/*processor for B4,B5*/ + switch (direction) { + case PICOPAM_DIR_FORW: + sDest = B4; + break; + case PICOPAM_DIR_BACK: + sDest = B5; + break; + default: + sDest = B4; + break; + } + if (event_type == PICOPAM_EVENT_SYLL) { + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[P1] == 0) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = pam->b4_b5_syllable; + pam->b4_b5_syllable++; + } else { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] = 0; + } + } + if ((event_type == PICOPAM_EVENT_W_BOUND) || (event_type + == PICOPAM_EVENT_S_BOUND) || (event_type + == PICOPAM_EVENT_P_BOUND)) { + pam->b4_b5_syllable = 1; + } + break; + case B5:/*processor for B5 : done in B4*/ + break; + case B6:/*processor for B6,B7*/ + switch (direction) { + case PICOPAM_DIR_FORW: + sDest = B6; + break; + case PICOPAM_DIR_BACK: + sDest = B7; + break; + default: + sDest = B6; + break; + } + switch (pam->b6_b7_state) { + case 0: + if (event_type == PICOPAM_EVENT_SYLL) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = PICOPAM_DONT_CARE_VALUE; + if (event_type == PICOPAM_EVENT_S_BOUND) { + pam->b6_b7_syllable = 1; + pam->b6_b7_state = 1; + } + break; + case 1: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = pam->b6_b7_syllable; + pam->b6_b7_syllable++; + } + if (event_type == PICOPAM_EVENT_S_BOUND) { + pam->b6_b7_syllable = 1; + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->b6_b7_state = 0; + } + break; + default: + break; + } + break; + case B7:/*Done in B6*/ + break; + case B8:/*processor for B8,B9*/ + switch (direction) { + case PICOPAM_DIR_FORW: + sDest = B8; + break; + case PICOPAM_DIR_BACK: + sDest = B9; + break; + default: + sDest = B8; + break; + } + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = pam->b8_b9_stressed_syllable; + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[B1] == 1) + pam->b8_b9_stressed_syllable++; + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->b8_b9_stressed_syllable = 0; + } + + break; + case B9:/*done in B8*/ + break; + case B10:/*processor for B10, B11*/ + switch (direction) { + case PICOPAM_DIR_FORW: + sDest = B10; + break; + case PICOPAM_DIR_BACK: + sDest = B11; + break; + default: + sDest = B10; + break; + } + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = pam->b10_b11_accented_syllable; + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[B2] == 1) + pam->b10_b11_accented_syllable++; + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->b10_b11_accented_syllable = 0; + } + break; + case B11:/*done in B10*/ + break; + case B12:/*processor for B12,B13*/ + switch (direction) { + case PICOPAM_DIR_FORW: + sDest = B12; + break; + case PICOPAM_DIR_BACK: + sDest = B13; + break; + default: + sDest = B12; + break; + } + switch (pam->b12_b13_state) { + case 0: + if (event_type == PICOPAM_EVENT_SYLL) { + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[B1] == 0) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = PICOPAM_DONT_CARE_VALUE; + else { + pam->b12_b13_syllable = 0; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = PICOPAM_DONT_CARE_VALUE; + pam->b12_b13_state = 1; + } + } + break; + case 1: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = pam->b12_b13_syllable; + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[B1] == 1) + pam->b12_b13_syllable = 0; + else + pam->b12_b13_syllable++; + pam->b12_b13_state = 2; + } + if (event_type == PICOPAM_EVENT_P_BOUND) + pam->b12_b13_state = 0; + break; + case 2: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = pam->b12_b13_syllable; + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[B1] == 1) + pam->b12_b13_syllable = 0; + else + pam->b12_b13_syllable++; + } + if (event_type == PICOPAM_EVENT_P_BOUND) + pam->b12_b13_state = 0; + + break; + default: + break; + } + break; + case B13:/*done in B12*/ + break; + + case B14:/*processor for B14, B15*/ + switch (direction) { + case PICOPAM_DIR_FORW: + sDest = B14; + break; + case PICOPAM_DIR_BACK: + sDest = B15; + break; + default: + sDest = B14; + break; + } + switch (pam->b14_b15_state) { + case 0: + if (event_type == PICOPAM_EVENT_SYLL) { + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[B2] == 0) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = PICOPAM_DONT_CARE_VALUE; + else { + pam->b14_b15_syllable = 0; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = PICOPAM_DONT_CARE_VALUE; + pam->b14_b15_state = 1; + } + } + break; + case 1: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = pam->b14_b15_syllable; + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[B2] == 1) + pam->b14_b15_syllable = 0; + else + pam->b14_b15_syllable++; + pam->b14_b15_state = 2; + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->b14_b15_state = 0; + } + break; + case 2: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = pam->b14_b15_syllable; + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[B2] == 1) + pam->b14_b15_syllable = 0; + else + pam->b14_b15_syllable++; + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->b14_b15_state = 0; + } + break; + default: + break; + } + break; + case B15:/*Processor for B15 : done in B14*/ + break; + case B16:/*done in createSyllable*/ + break; + case B17:/*processor for B17, B19 unified */ + switch (direction) { + case PICOPAM_DIR_FORW: + switch (pam->b17_b19_state) { + case 0: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B17] + = PICOPAM_DONT_CARE_VALUE; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B19] + = pam->b17_b19_syllable; + pam->b17_b19_syllable++; + } + if (((event_type == PICOPAM_EVENT_P_BOUND) + || (event_type == PICOPAM_EVENT_S_BOUND)) + && (pam->b17_b19_syllable > 1)) { + if (event_type == PICOPAM_EVENT_P_BOUND) + pam->b17_b19_syllable = 1; + pam->b17_b19_state = 1; + } + break; + case 1: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B17] + = pam->b17_b19_syllable; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B19] + = PICOPAM_DONT_CARE_VALUE; + pam->b17_b19_syllable++; + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->b17_b19_syllable = 1; + } + break; + default: + break; + } + break; + case PICOPAM_DIR_BACK: + /*do nothing*/ + break; + } + break; + case B18:/*processor for B18, B20, B21 unfied*/ + switch (direction) { + case PICOPAM_DIR_FORW:/*do nothing*/ + break; + case PICOPAM_DIR_BACK: + switch (pam->b18_b20_b21_state) { + case 0: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B18] + = PICOPAM_DONT_CARE_VALUE; + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[P6] + == PICOPAM_DECLARATIVE) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B20] + = pam->b18_b20_b21_syllable; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B21] + = PICOPAM_DONT_CARE_VALUE; + } else { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B20] + = PICOPAM_DONT_CARE_VALUE; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B21] + = pam->b18_b20_b21_syllable; + } + pam->b18_b20_b21_syllable++; + } + if (((event_type == PICOPAM_EVENT_P_BOUND) + || (event_type == PICOPAM_EVENT_S_BOUND)) + && (pam->b18_b20_b21_syllable > 1)) { + if (event_type == PICOPAM_EVENT_P_BOUND) + pam->b18_b20_b21_syllable = 1; + pam->b18_b20_b21_state = 1; + } + break; + case 1: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B18] + = pam->b18_b20_b21_syllable; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B20] + = PICOPAM_DONT_CARE_VALUE; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B21] + = PICOPAM_DONT_CARE_VALUE; + pam->b18_b20_b21_syllable++; + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->b18_b20_b21_syllable = 1; + } + break; + default: + break; + } + break; + } + break; + case B19:/*processor for B19 : done in B17*/ + break; + case B20:/*processor for B20 : done in B18*/ + break; + case B21:/*processor for B21 : done in B18*/ + break; + case C3:/*processor for C3*/ + switch (direction) { + case PICOPAM_DIR_FORW: + /*do nothing*/ + break; + case PICOPAM_DIR_BACK: + if (event_type == PICOPAM_EVENT_SYLL) { + if ((pam->sSyllFeats[pam->nCurrSyllable].phoneV[P1] + == 1) || (pam->c3_primary_phrase_syllable >= 1)) { + if (pam->c3_overall_syllable < 1) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[C3] + = 0; + else + pam->sSyllFeats[pam->nCurrSyllable].phoneV[C3] + = pam->sSyllFeats[pam->nCurrSyllable + + 1].phoneV[B3]; + } else { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[C3] = 0; + } + pam->c3_primary_phrase_syllable++; + pam->c3_overall_syllable++; + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->c3_primary_phrase_syllable = 0; + } + break; + } + break; + case D2:/*processor for D2*/ + switch (direction) { + case PICOPAM_DIR_FORW: + if (event_type == PICOPAM_EVENT_SYLL) { + if ((pam->sSyllFeats[pam->nCurrSyllable].phoneV[P1] + == 1) || (pam->d2_current_primary_phrase_word + >= 1)) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[D2] + = pam->d2_prev_syllable_in_word; + else + pam->sSyllFeats[pam->nCurrSyllable].phoneV[D2] = 0; + + pam->d2_syllable_in_word++; + } + if ((event_type == PICOPAM_EVENT_W_BOUND) || (event_type + == PICOPAM_EVENT_S_BOUND) || (event_type + == PICOPAM_EVENT_P_BOUND)) { + pam->d2_current_primary_phrase_word = 1; + pam->d2_prev_syllable_in_word + = pam->d2_syllable_in_word; + pam->d2_syllable_in_word = 0; + /*pam->d2_current_primary_phrase_word++;*/ + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->d2_current_primary_phrase_word = 0; + } + break; + case PICOPAM_DIR_BACK: + /*do nothing*/ + break; + } + break; + case E1:/*processor for E1*/ + switch (direction) { + case PICOPAM_DIR_FORW: /*remember : content syllable indicator already on P5*/ + if (event_type == PICOPAM_EVENT_SYLL) { + if (pam->e1_syllable_word_start == -1) + pam->e1_syllable_word_start + = (picoos_int8) pam->nCurrSyllable; + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[P5] == 1) + pam->e1_content = 1; + pam->e1_syllable_word_end + = (picoos_int8) pam->nCurrSyllable; + } + if ((event_type == PICOPAM_EVENT_W_BOUND) || (event_type + == PICOPAM_EVENT_S_BOUND) || (event_type + == PICOPAM_EVENT_P_BOUND)) { + if ((pam->e1_syllable_word_start != -1) + && (pam->e1_syllable_word_end != -1)) { + for (nI = pam->e1_syllable_word_start; nI + <= pam->e1_syllable_word_end; nI++) + pam->sSyllFeats[nI].phoneV[E1] + = pam->e1_content; + } + pam->e1_content = 0; + pam->e1_syllable_word_start = -1; + pam->e1_syllable_word_end = -1; + } + break; + case PICOPAM_DIR_BACK: + /*do nothing*/ + break; + } + break; + case E2:/*processor for E2*/ + switch (direction) { + case PICOPAM_DIR_FORW: + if (event_type == PICOPAM_EVENT_SYLL) { + if (pam->e2_syllable_word_start == -1) + pam->e2_syllable_word_start + = (picoos_int8) pam->nCurrSyllable; + pam->e2_syllable_word_end + = (picoos_int8) pam->nCurrSyllable; + } + if ((event_type == PICOPAM_EVENT_W_BOUND) || (event_type + == PICOPAM_EVENT_S_BOUND) || (event_type + == PICOPAM_EVENT_P_BOUND)) { + if ((pam->e2_syllable_word_start != -1) + && (pam->e2_syllable_word_end != -1)) { + for (nI = pam->e2_syllable_word_start; nI + <= pam->e2_syllable_word_end; nI++) + pam->sSyllFeats[nI].phoneV[E2] + = pam->e2_syllable_word_end + - pam->e2_syllable_word_start + + 1; + } + pam->e1_content = 0; + pam->e2_syllable_word_start = -1; + pam->e2_syllable_word_end = -1; + } + break; + case PICOPAM_DIR_BACK: + break; + } + break; + case E3:/*processor for E3,E4*/ + switch (direction) { + case PICOPAM_DIR_FORW: + sDest = E3; + break; + case PICOPAM_DIR_BACK: + sDest = E4; + break; + default: + sDest = E3; + break; + } + switch (pam->e3_e4_state) { + case 0: + if (event_type == PICOPAM_EVENT_SYLL) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = PICOPAM_DONT_CARE_VALUE; + if (event_type == PICOPAM_EVENT_S_BOUND) { + pam->e3_e4_word = 1; + pam->e3_e4_state = 1; + } + break; + case 1: + if (event_type == PICOPAM_EVENT_SYLL) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = pam->e3_e4_word; + if (event_type == PICOPAM_EVENT_S_BOUND) + pam->e3_e4_word = 1; + if (event_type == PICOPAM_EVENT_W_BOUND) + pam->e3_e4_word++; + if (event_type == PICOPAM_EVENT_P_BOUND) + pam->e3_e4_state = 0; + break; + default: + break; + } + break; + case E4:/*processor for E4 : done in E3*/ + break; + case E5:/*processor for E5,E6*/ + switch (direction) { + case PICOPAM_DIR_FORW: + sDest = E5; + break; + case PICOPAM_DIR_BACK: + sDest = E6; + break; + default: + sDest = E5; + break; + } + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = pam->e5_e6_content_word; + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[P5] == 1) + pam->e5_e6_content = 1; + } + if ((event_type == PICOPAM_EVENT_W_BOUND) || (event_type + == PICOPAM_EVENT_S_BOUND) || (event_type + == PICOPAM_EVENT_P_BOUND)) { + if (pam->e5_e6_content == 1) + pam->e5_e6_content_word++; + pam->e5_e6_content = 0; + if (event_type == PICOPAM_EVENT_P_BOUND) + pam->e5_e6_content_word = 0; + } + break; + case E6:/*processor for E6 : done in E5*/ + break; + case E7:/*processor for E7,E8*/ + switch (direction) { + case PICOPAM_DIR_FORW: + sDest = E7; + break; + case PICOPAM_DIR_BACK: + sDest = E8; + break; + default: + sDest = E7; + break; + } + switch (pam->e7_e8_state) { + case 0: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = PICOPAM_DONT_CARE_VALUE; + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[P5] == 1) + pam->e7_e8_content = 1; + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->e7_e8_content = 0; + } + + if ((event_type == PICOPAM_EVENT_W_BOUND) || (event_type + == PICOPAM_EVENT_S_BOUND)) { + if (pam->e7_e8_content == 1) { + pam->e7_e8_word = 0; + pam->e7_e8_content = 0; + pam->e7_e8_state = 1; + } + } + break; + case 1: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = pam->e7_e8_word; + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[P5] == 1) + pam->e7_e8_content = 1; + } + if ((event_type == PICOPAM_EVENT_W_BOUND) || (event_type + == PICOPAM_EVENT_S_BOUND)) { + if (pam->e7_e8_content == 1) { + pam->e7_e8_word = 0; + pam->e7_e8_content = 0; + } else { + pam->e7_e8_word++; + } + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->e7_e8_state = 0; + pam->e7_e8_content = 0; /*<<<<<< added */ + } + + default: + break; + } + break; + case E8:/*processor for E8 : done in E7*/ + break; + case E9: + /*processor for E9, E11*/ + switch (direction) { + case PICOPAM_DIR_FORW: + switch (pam->e9_e11_state) { + case 0: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E9] + = PICOPAM_DONT_CARE_VALUE; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E11] + = pam->e9_e11_word; + pam->e9_e11_saw_word = 1; /*new variable, needs to be initialized to 0*/ + } + if (event_type == PICOPAM_EVENT_W_BOUND) + pam->e9_e11_word++; + if (((event_type == PICOPAM_EVENT_P_BOUND) + || (event_type == PICOPAM_EVENT_S_BOUND)) + && (pam->e9_e11_saw_word == 1)) { /* modified*/ + if (event_type == PICOPAM_EVENT_P_BOUND) + pam->e9_e11_word = 1; + else + pam->e9_e11_word++; /*modified*/ + pam->e9_e11_state = 1; + } + break; + case 1: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E9] + = pam->e9_e11_word; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E11] + = PICOPAM_DONT_CARE_VALUE; + } + if ((event_type == PICOPAM_EVENT_W_BOUND) + || (event_type == PICOPAM_EVENT_S_BOUND)) + pam->e9_e11_word++; + if (event_type == PICOPAM_EVENT_P_BOUND) + pam->e9_e11_word = 1; + break; + default: + break; + } + break; + case PICOPAM_DIR_BACK: + /*do nothing*/ + break; + } + break; + case E10:/*processor for E10, E12, E13 unified*/ + switch (direction) { + case PICOPAM_DIR_FORW:/*do nothing*/ + break; + case PICOPAM_DIR_BACK: + switch (pam->e10_e12_e13_state) { + case 0: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E10] + = PICOPAM_DONT_CARE_VALUE; + pam->e10_e12_e13_saw_word = 1; + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[P6] + == PICOPAM_DECLARATIVE) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E12] + = pam->e10_e12_e13_word; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E13] + = PICOPAM_DONT_CARE_VALUE; + } else { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E12] + = PICOPAM_DONT_CARE_VALUE; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E13] + = pam->e10_e12_e13_word; + } + } + if (event_type == PICOPAM_EVENT_W_BOUND) + pam->e10_e12_e13_word++; + + /*if (((event_type==PICOPAM_EVENT_P_BOUND)||(event_type==PICOPAM_EVENT_S_BOUND))&&(pam->e10_e12_e13_word>1)) {*/ + if (((event_type == PICOPAM_EVENT_P_BOUND) + || (event_type == PICOPAM_EVENT_S_BOUND)) + && (pam->e10_e12_e13_saw_word > 0)) { + if (event_type == PICOPAM_EVENT_P_BOUND) + pam->e10_e12_e13_word = 1; + else + pam->e10_e12_e13_word++; + pam->e10_e12_e13_state = 1; + } + break; + case 1: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E10] + = pam->e10_e12_e13_word; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E12] + = PICOPAM_DONT_CARE_VALUE; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E13] + = PICOPAM_DONT_CARE_VALUE; + } + if ((event_type == PICOPAM_EVENT_W_BOUND) + || (event_type == PICOPAM_EVENT_S_BOUND)) + pam->e10_e12_e13_word++; + if (event_type == PICOPAM_EVENT_P_BOUND) + pam->e10_e12_e13_word = 1; + break; + default: + break; + } + break; + } + break; + + case E11:/*processor for E11 : done in E9*/ + break; + case E12:/*processor for E12 : done in E10*/ + break; + case E13:/*processor for E13 : done in E10*/ + break; + + case F2: + switch (direction) { + case PICOPAM_DIR_FORW:/*do nothing*/ + break; + case PICOPAM_DIR_BACK: + if (event_type == PICOPAM_EVENT_SYLL) { + if (pam->f2_current_primary_phrase_word >= 1)/*at least second word in current primary phrase*/ + pam->sSyllFeats[pam->nCurrSyllable].phoneV[F2] + = pam->f2_next_word_syllable; + else + /*first word in current primary phrase*/ + pam->sSyllFeats[pam->nCurrSyllable].phoneV[F2] = 0; + pam->f2_word_syllable++; + } + if ((event_type == PICOPAM_EVENT_W_BOUND) || (event_type + == PICOPAM_EVENT_S_BOUND) || (event_type + == PICOPAM_EVENT_P_BOUND)) {/*word - end : switch*/ + pam->f2_next_word_syllable = pam->f2_word_syllable; + pam->f2_word_syllable = 0; + } + if (event_type == PICOPAM_EVENT_P_BOUND)/*mark first word in current primary phrase*/ + pam->f2_current_primary_phrase_word = 0; + else /*mark next word in current primary phrase(enables output in PICOPAM_EVENT_SYLL)*/ + if ((event_type == PICOPAM_EVENT_W_BOUND) || (event_type + == PICOPAM_EVENT_S_BOUND)) + pam->f2_current_primary_phrase_word++; + break; + } + break; + case G1: + switch (direction) { + case PICOPAM_DIR_FORW: + if (event_type == PICOPAM_EVENT_SYLL) { + if (pam->g1_current_secondary_phrase_syllable > 0) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[G1] + = pam->g1_current_secondary_phrase_syllable; + else + pam->sSyllFeats[pam->nCurrSyllable].phoneV[G1] = 0; + pam->g1_current_syllable++; + } + if (event_type == PICOPAM_EVENT_S_BOUND) { + pam->g1_current_secondary_phrase_syllable + = pam->g1_current_syllable; + pam->g1_current_syllable = 0; + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->g1_current_secondary_phrase_syllable = 0; + pam->g1_current_syllable = 0; + } + case PICOPAM_DIR_BACK: /*do nothing*/ + break; + } + break; + case G2: + switch (direction) { + case PICOPAM_DIR_FORW: + if (event_type == PICOPAM_EVENT_SYLL) { + if (pam->g2_current_secondary_phrase_word > 0) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[G2] + = pam->g2_current_secondary_phrase_word; + else + pam->sSyllFeats[pam->nCurrSyllable].phoneV[G2] = 0; + } + if (event_type == PICOPAM_EVENT_W_BOUND) + pam->g2_current_word++; + + if (event_type == PICOPAM_EVENT_S_BOUND) { + pam->g2_current_secondary_phrase_word + = pam->g2_current_word + 1; + pam->g2_current_word = 0; + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->g2_current_secondary_phrase_word = 0; + pam->g2_current_word = 0; + } + break; + case PICOPAM_DIR_BACK: /*do nothing*/ + break; + } + break; + case H1: + switch (direction) { + case PICOPAM_DIR_FORW: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->h1_current_secondary_phrase_syll++; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[H1] + = pam->h1_current_secondary_phrase_syll; + } + if ((event_type == PICOPAM_EVENT_S_BOUND) || (event_type + == PICOPAM_EVENT_P_BOUND)) + pam->h1_current_secondary_phrase_syll = 0; + break; + case PICOPAM_DIR_BACK: + if (event_type == PICOPAM_EVENT_SYLL) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[H1] + = pam->h1_current_secondary_phrase_syll; + if (event_type == PICOPAM_EVENT_S_BOUND) + pam->h1_current_secondary_phrase_syll + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[H1]; + if (event_type == PICOPAM_EVENT_P_BOUND) + pam->h1_current_secondary_phrase_syll + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[H1]; + break; + } + break; + case H2: + switch (direction) { + case PICOPAM_DIR_FORW: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[H2] + = pam->h2_current_secondary_phrase_word; + } + if (event_type == PICOPAM_EVENT_W_BOUND) { + pam->h2_current_secondary_phrase_word++; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[H2] + = pam->h2_current_secondary_phrase_word; + } + if (event_type == PICOPAM_EVENT_S_BOUND) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[H2] + = pam->h2_current_secondary_phrase_word + 1; + pam->h2_current_secondary_phrase_word = 0; + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + if (pam->nCurrSyllable > 1) + pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[H2] + = pam->h2_current_secondary_phrase_word + 1; + pam->h2_current_secondary_phrase_word = 0; + } + break; + case PICOPAM_DIR_BACK: + if (event_type == PICOPAM_EVENT_SYLL) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[H2] + = pam->h2_current_secondary_phrase_word; + if (event_type == PICOPAM_EVENT_S_BOUND) + pam->h2_current_secondary_phrase_word + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[H2]; + if (event_type == PICOPAM_EVENT_P_BOUND) + pam->h2_current_secondary_phrase_word + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[H2]; + break; + } + break; + case H3:/*processor for H3,H4 unified */ + switch (direction) { + case PICOPAM_DIR_FORW: + sDest = H3; + break; + case PICOPAM_DIR_BACK: + sDest = H4; + break; + default: + sDest = H3; + break; + } + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[sDest] + = pam->h3_h4_current_secondary_phrase_word; + } + if ((event_type == PICOPAM_EVENT_S_BOUND) || (event_type + == PICOPAM_EVENT_P_BOUND)) + pam->h3_h4_current_secondary_phrase_word++; + break; + case H4: /*processor for H4 : already in H3*/ + break; + + case H5:/*processor for H5*/ + switch (direction) { + case PICOPAM_DIR_FORW: + break; + case PICOPAM_DIR_BACK: + switch (pam->h5_state) { + case 0: + if (event_type == PICOPAM_EVENT_SYLL) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[H5] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[H5]; + if (event_type == PICOPAM_EVENT_S_BOUND) { + pam->h5_state = 1; + } + break; + case 1: + if (event_type == PICOPAM_EVENT_SYLL) { + if ((pam->sSyllFeats[pam->nCurrSyllable].phoneV[H5] + == PICOPAM_P) + && (pam->sSyllFeats[pam->nCurrSyllable].phoneV[P1] + == 0)) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[H5] + = PICOPAM_p; + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->h5_state = 0; + } + break; + default: + break; + } + break; + + default: + break; + } + break; + + case I1:/*processor for I1*/ + switch (direction) { + case PICOPAM_DIR_FORW: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->i1_secondary_phrase_syllable++; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[I1] + = pam->i1_secondary_phrase_syllable; + } + if ((event_type == PICOPAM_EVENT_S_BOUND) || (event_type + == PICOPAM_EVENT_P_BOUND)) + pam->i1_secondary_phrase_syllable = 0; + break; + case PICOPAM_DIR_BACK: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[I1] + = pam->i1_next_secondary_phrase_syllable; + } + if (event_type == PICOPAM_EVENT_S_BOUND) { + pam->i1_next_secondary_phrase_syllable + = pam->i1_secondary_phrase_syllable; + pam->i1_secondary_phrase_syllable + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[I1]; + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->i1_next_secondary_phrase_syllable = 0; + pam->i1_secondary_phrase_syllable + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[I1]; + } + break; + } + break; + case I2: /*processor for I2*/ + switch (direction) { + case PICOPAM_DIR_FORW: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[I2] + = pam->i2_secondary_phrase_word; + } + if (event_type == PICOPAM_EVENT_W_BOUND) + pam->i2_secondary_phrase_word++; + + if ((event_type == PICOPAM_EVENT_P_BOUND) || (event_type + == PICOPAM_EVENT_S_BOUND)) + pam->i2_secondary_phrase_word = 1; + + break; + case PICOPAM_DIR_BACK: + if (event_type == PICOPAM_EVENT_SYLL) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[I2] + = pam->i2_next_secondary_phrase_word; + } + if (event_type == PICOPAM_EVENT_S_BOUND) { + pam->i2_next_secondary_phrase_word + = pam->i2_secondary_phrase_word; + pam->i2_secondary_phrase_word + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[I2]; + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->i2_next_secondary_phrase_word = 0; + pam->i2_secondary_phrase_word + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[I2]; + } + break; + } + break; + case J1: /*processor for J1 */ + switch (direction) { + case PICOPAM_DIR_FORW: + if (event_type == PICOPAM_EVENT_SYLL) { + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[P1] != 1) + pam->j1_utterance_syllable++; + } + break; + case PICOPAM_DIR_BACK: + pam->sSyllFeats[pam->nCurrSyllable].phoneV[J1] + = pam->j1_utterance_syllable; + break; + } + break; + case J2: /*processor for J2*/ + switch (direction) { + case PICOPAM_DIR_FORW: + if ((event_type == PICOPAM_EVENT_W_BOUND) || (event_type + == PICOPAM_EVENT_S_BOUND) || (event_type + == PICOPAM_EVENT_P_BOUND)) + pam->j2_utterance_word++; + break; + case PICOPAM_DIR_BACK: + pam->sSyllFeats[pam->nCurrSyllable].phoneV[J2] + = pam->j2_utterance_word - 1; + break; + } + break; + case J3: /*processor for J3*/ + switch (direction) { + case PICOPAM_DIR_FORW: + if (event_type == PICOPAM_EVENT_S_BOUND) { + pam->j3_utterance_sec_phrases++; + break; + } + if (event_type == PICOPAM_EVENT_P_BOUND) { + pam->j3_utterance_sec_phrases++; + break; + } + break; + case PICOPAM_DIR_BACK: + pam->sSyllFeats[pam->nCurrSyllable].phoneV[J3] + = pam->j3_utterance_sec_phrases - 1; + break; + } + break; + } + return PICO_OK; +}/*pam_process_event_feature*/ + +/** + * processes an input event spanning it to all column features + * @param this : pointer to PAM PU sub object pointer + * @param event_type : event id among syll/boundprim/boundsec/boundword + * @param direction : forward(0)/backward(1) + * @return PICO_OK : process OK + * @return PICO_ERR_OTHER : errors on getting pam sub obj pointer + * @callgraph + * @callergraph + */ +static pico_status_t pam_process_event(register picodata_ProcessingUnit this, + picoos_uint8 event_type, picoos_uint8 direction) +{ + picoos_uint8 nFeat; + pico_status_t nResult; + + pam_subobj_t *pam; + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + pam = (pam_subobj_t *) this->subObj; + + if (direction == PICOPAM_DIR_FORW) { + if (event_type == PICOPAM_EVENT_P_BOUND) + /*primary boundary*/ + pam->sSyllFeats[pam->nCurrSyllable].phoneV[P2] = 1; + if (event_type == PICOPAM_EVENT_S_BOUND) + /*secondary boundary*/ + pam->sSyllFeats[pam->nCurrSyllable].phoneV[P3] = 1; + if (event_type == PICOPAM_EVENT_W_BOUND) + /*word boundary*/ + pam->sSyllFeats[pam->nCurrSyllable].phoneV[P4] = 1; + } + for (nFeat = A3; nFeat <= J3; nFeat++) { + nResult = pam_process_event_feature(this, nFeat, event_type, direction); + if (nResult != PICO_OK) + return nResult; + } + return PICO_OK; +}/*pam_process_event*/ + +/** + * inserts a syllable inside the subobj sentence data struct. + * @param this : pointer to PAM PU sub object pointer + * @param syllType : the syllable type (pause/syllable) + * @param sContent : the item content + * @param sentType : the sentence type + * @param phType : the phrase type + * @param uBoundType : the boundary type (only for silence syllables) + * @param uMinDur, uMaxDur : the mimimum and maximum duration (only for silence syllables) + * @return PICO_OK : syllable creation successful + * @return PICO_ERR_OTHER : errors in one internal function (check_phones_size..) + * @callgraph + * @callergraph + */ +static pico_status_t pam_create_syllable(register picodata_ProcessingUnit this, + picoos_uint8 syllType, picoos_uint8 *sContent, picoos_uint8 sentType, + picoos_uint8 phType, picoos_uint8 uBoundType, picoos_uint16 uMinDur, + picoos_uint16 uMaxDur) +{ + pam_subobj_t *pam; + picoos_uint8 nI; + picoos_uint8 pos; + /* picoos_uint8 *npUi16; */ + picoos_uint32 pos32; + + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + pam = (pam_subobj_t *) this->subObj; + pos = 0; + /*check buffer full condition on number of syllables*/ + if (check_syllables_size(pam, 1) != PICO_OK) { + return PICO_ERR_OTHER; + } + + if (syllType == PICOPAM_SYLL_PAUSE) { + /*check buffer full condition on number of phonemes*/ + if (check_phones_size(pam, 1) != PICO_OK) { + return PICO_ERR_OTHER; + } + } + if (syllType == PICOPAM_SYLL_SYLL) { + /*check item availability*/ + if (sContent == NULL) { + return PICO_ERR_OTHER; + } + /*check buffer full condition on number of phonemes*/ + if (check_phones_size(pam, sContent[3]) != PICO_OK) { + return PICO_ERR_OTHER; + } + } + + /*open new syllable*/ + pam->nCurrSyllable = pam->nCurrSyllable + 1; + /*cleanup*/ + for (nI = 0; nI < PICOPAM_VECT_SIZE; nI++) { + if (pam->nCurrSyllable > 0) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[nI] = 0; + } else { + if ((nI >= ITM) && (nI <= itm)) { + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[nI] > 0) { + /*do not cleanup "attached item offset" fields (ITM, itm): + an already existing attached item could be lost*/ + } else { + /*cleanup "attached item offset"*/ + pam->sSyllFeats[pam->nCurrSyllable].phoneV[nI] = 0; + } + } else { + /*cleanup all fields except "attached item offset" (ITM, itm)*/ + pam->sSyllFeats[pam->nCurrSyllable].phoneV[nI] = 0; + } + } + } + /*set minimum and maximum duration values*/ + if ((uMinDur == 0) && (uMaxDur == 0) && (syllType == PICOPAM_SYLL_PAUSE)) { + /*both 0 : use default duration limits for boundaries*/ + get_default_boundary_limit(uBoundType, &uMinDur, &uMaxDur); + } + if (uMinDur > 0) { + pos32 = Min; + picoos_write_mem_pi_uint16(pam->sSyllFeats[pam->nCurrSyllable].phoneV, + &pos32, uMinDur); + } + if (uMaxDur > 0) { + pos32 = Max; + picoos_write_mem_pi_uint16(pam->sSyllFeats[pam->nCurrSyllable].phoneV, + &pos32, uMaxDur); + } + /*END OF BREAK COMMAND SUPPORT*/ + + if (syllType == PICOPAM_SYLL_PAUSE) { + /*initialize a pause syllable*/ + if (sentType == PICOPAM_DECLARATIVE) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[P6] + = PICOPAM_DECLARATIVE; + if (sentType == PICOPAM_INTERROGATIVE) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[P6] + = PICOPAM_INTERROGATIVE; + + pam->sSyllFeats[pam->nCurrSyllable].phoneV[bnd] = uBoundType; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[P1] = 1; /*this means the syllable contains a pause-silence*/ + pam->sSyllFeats[pam->nCurrSyllable].phoneV[P8] = 1; + + /*b1,b2,b9,b11,b13,b15,e1,e6,e8,e10 already set to 0*/ + + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B3] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[B4] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[B5] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[B6] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[B7] + = 1; + + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B16] + = PICOPAM_PH_DONT_CARE_VAL; /*name of the vowel in the syllable = NONE */ + + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E2] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[E3] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[E4] = 1; + + pam->sSyllFeats[pam->nCurrSyllable].phoneV[H5] = phType; + + /*Store current phonetic codes in input phonetic string*/ + pam->sPhIds[pam->nCurrPhoneme] = pam_get_pause_id(this); + picoos_mem_copy((void*) &pam->nCurrPhoneme, + &(pam->sSyllFeats[pam->nCurrSyllable].phoneV[FID]), + sizeof(pam->nCurrPhoneme)); + pam->nCurrPhoneme++; + pam->nTotalPhonemes++; + /*add 1 to total number of syllables*/ + pam->nTotalSyllables++; + + return PICO_OK; + } + if (syllType == PICOPAM_SYLL_SYLL) { + /*initialize a real syllable*/ + if (sContent[2] > PICODATA_ACC0) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[P5] = 1; /*set content syllable indicator*/ + if (sentType == PICOPAM_DECLARATIVE) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[P6] + = PICOPAM_DECLARATIVE; + if (sentType == PICOPAM_INTERROGATIVE) + pam->sSyllFeats[pam->nCurrSyllable].phoneV[P6] + = PICOPAM_INTERROGATIVE; + + if ((sContent[2] >= PICODATA_ACC1) && (sContent[2] <= PICODATA_ACC4)) + /*stressed*/ + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B1] = 1; + + if ((sContent[2] >= PICODATA_ACC1) && (sContent[2] <= PICODATA_ACC2)) + /*accented*/ + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B2] = 1; + + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B3] = sContent[3];/*len*/ + + if (pam->nCurrSyllable > 30) + pam->nCurrSyllable = pam->nCurrSyllable; + + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B16] = pam_get_vowel_name(this, + sContent, &pos); /*name of the vowel in the syllable*/ + + pam->sSyllFeats[pam->nCurrSyllable].phoneV[P8] = pos; /*temp for storing the position of the vowel*/ + + pam->sSyllFeats[pam->nCurrSyllable].phoneV[H5] = phType; + + /*Store current phonetic codes in input phonetic string*/ + picoos_mem_copy((void*) &pam->nCurrPhoneme, + &(pam->sSyllFeats[pam->nCurrSyllable].phoneV[FID]), + sizeof(pam->nCurrPhoneme)); + for (nI = 0; nI < sContent[3]; nI++) + pam->sPhIds[pam->nCurrPhoneme + nI] = sContent[4 + nI]; + pam->nCurrPhoneme += nI; + pam->nTotalPhonemes += nI; + /*add 1 to total number of syllables*/ + pam->nTotalSyllables++; + return PICO_OK; + } + /*if no SyllType has been identified -->> error*/ + return PICO_ERR_OTHER; +}/*pam_create_syllable*/ + +/** + * performs the forward step of the PAM adapter + * @param this : pointer to PAM PU sub object pointer + * @param itemBase : pointer to current item + * @return PICOPAM_READY : forward step ok, the sentence is complete + * @return PICOPAM_MORE : forward step ok, but more data needed to complete the sentence + * @return PICO_ERR_OTHER : errors in one internal function (CreateSyllable..) + * @callgraph + * @callergraph + */ +static pico_status_t pam_adapter_forward_step( + register picodata_ProcessingUnit this, picoos_uint8 *itemBase) +{ + register pam_subobj_t * pam; + pico_status_t sResult; + picoos_uint16 uMinDur, uMaxDur; + picoos_uint32 nPos; + + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + pam = (pam_subobj_t *) this->subObj; + uMinDur = uMaxDur = 0; /*default 0 : not initialized*/ + switch (itemBase[0]) { + case PICODATA_ITEM_BOUND: + /*received a boundary item*/ + switch (itemBase[1]) { + case PICODATA_ITEMINFO1_BOUND_SBEG: + case PICODATA_ITEMINFO1_BOUND_PHR1: +#ifdef PAM_PHR2_WITH_PR1 + case PICODATA_ITEMINFO1_BOUND_PHR2: +#endif + case PICODATA_ITEMINFO1_BOUND_SEND: + case PICODATA_ITEMINFO1_BOUND_TERM: + if (itemBase[3] == 2 * sizeof(picoos_uint16)) { + /*only when the item len duration is equal to 2 int16 --> get the values*/ + nPos = 4; + picoos_read_mem_pi_uint16(itemBase, &nPos, &uMinDur); + picoos_read_mem_pi_uint16(itemBase, &nPos, &uMaxDur); + } + break; + default: + break; + } + switch (itemBase[1]) { + case PICODATA_ITEMINFO1_BOUND_SBEG: + /* received a sentence init boundary */ + pam_reset_processors(this); /*reset all processor variables*/ + pam->sType + = pam_map_sentence_type(itemBase[1], itemBase[2]); + pam->pType = pam_map_phrase_type(itemBase[1], itemBase[2]); + /*create silence syll and process P_BOUND event*/ + sResult = pam_create_syllable(this, PICOPAM_SYLL_PAUSE, NULL, + pam->sType, pam->pType, itemBase[1], uMinDur, + uMaxDur); + if (sResult != PICO_OK) + return sResult; + sResult = pam_process_event(this, PICOPAM_EVENT_P_BOUND, + PICOPAM_DIR_FORW); + if (sResult != PICO_OK) + return sResult; + return PICOPAM_MORE; + break; + + case PICODATA_ITEMINFO1_BOUND_PHR1: +#ifdef PAM_PHR2_WITH_PR1 + case PICODATA_ITEMINFO1_BOUND_PHR2: +#endif + /*received a primary boundary*/ + pam->sType + = pam_map_sentence_type(itemBase[1], itemBase[2]); + pam->pType = pam_map_phrase_type(itemBase[1], itemBase[2]); + /*create silence syll and process P_BOUND event*/ + sResult = pam_create_syllable(this, PICOPAM_SYLL_PAUSE, NULL, + pam->sType, pam->pType, itemBase[1], uMinDur, + uMaxDur); + if (sResult != PICO_OK) + return sResult; + sResult = pam_process_event(this, PICOPAM_EVENT_P_BOUND, + PICOPAM_DIR_FORW); + if (sResult != PICO_OK) + return sResult; + return PICOPAM_MORE; + break; + +#ifdef PAM_PHR2_WITH_PR3 + case PICODATA_ITEMINFO1_BOUND_PHR2 : +#endif + case PICODATA_ITEMINFO1_BOUND_PHR3: + /*received a secondary boundary*/ + /*process S_BOUND event*/ + sResult = pam_process_event(this, PICOPAM_EVENT_S_BOUND, + PICOPAM_DIR_FORW); + /*determine new sentence and Phrase types for following syllables*/ + pam->sType + = pam_map_sentence_type(itemBase[1], itemBase[2]); + pam->pType = pam_map_phrase_type(itemBase[1], itemBase[2]); + if (sResult != PICO_OK) + return sResult; + return PICOPAM_MORE; + break; + + case PICODATA_ITEMINFO1_BOUND_PHR0: + /*received a word end boundary*/ + /*process W_BOUND event*/ + sResult = pam_process_event(this, PICOPAM_EVENT_W_BOUND, + PICOPAM_DIR_FORW); + if (sResult != PICO_OK) + return sResult; + return PICOPAM_MORE; + break; + + case PICODATA_ITEMINFO1_BOUND_SEND: + /*received a SEND boundary*/ + /*insert a new silence syllable and process P_BOUND event*/ + /*create silence syll and process P_BOUND event*/ + sResult = pam_create_syllable(this, PICOPAM_SYLL_PAUSE, NULL, + pam->sType, pam->pType, itemBase[1], uMinDur, + uMaxDur); + if (sResult != PICO_OK) + return sResult; + sResult = pam_process_event(this, PICOPAM_EVENT_P_BOUND, + PICOPAM_DIR_FORW); + if (sResult != PICO_OK) + return sResult; + return PICOPAM_READY; + break; + + case PICODATA_ITEMINFO1_BOUND_TERM: + /* received a flush boundary*/ + if (pam->nCurrSyllable == -1) { + return PICOPAM_NA; + } + /*insert a new silence syllable and process P_BOUND event*/ + /*create silence syll and process P_BOUND event*/ + sResult = pam_create_syllable(this, PICOPAM_SYLL_PAUSE, NULL, + pam->sType, pam->pType, itemBase[1], uMinDur, + uMaxDur); + if (sResult != PICO_OK) + return sResult; + sResult = pam_process_event(this, PICOPAM_EVENT_P_BOUND, + PICOPAM_DIR_FORW); + if (sResult != PICO_OK) + return sResult; + return PICOPAM_READY; + break; + + default: + /*boundary type not known*/ + return PICOPAM_NA; + break; + }/*end switch (itemBase[1])*/ + break; /*end case PICODATA_ITEM_BOUND*/ + + case PICODATA_ITEM_SYLLPHON: + /*received a syllable item*/ + /* ------------------------------------------------------------------ + following code has to be used if we do expect + SYLL items arrive even without SBEG items starting the sentence. + this may happen after a term has been issued to make room in local storage. + */ + if (pam->nCurrSyllable == -1) { + pam_reset_processors(this); + /*insert an SBEG with sType and pType taken from previous sentence*/ + sResult = pam_create_syllable(this, PICOPAM_SYLL_PAUSE, NULL, + pam->sType, pam->pType, PICODATA_ITEMINFO1_BOUND_SBEG, + 0, 0); + if (sResult != PICO_OK) + return sResult; + sResult = pam_process_event(this, PICOPAM_EVENT_P_BOUND, + PICOPAM_DIR_FORW); + if (sResult != PICO_OK) + return sResult; + } + /* ------------------------------------------------------------------*/ + sResult = pam_create_syllable(this, PICOPAM_SYLL_SYLL, itemBase, + pam->sType, pam->pType, 0, 0, 0); + if (sResult != PICO_OK) + return sResult; + sResult = pam_process_event(this, PICOPAM_EVENT_SYLL, + PICOPAM_DIR_FORW); + if (sResult != PICO_OK) + return sResult; + return PICOPAM_MORE; + break; + + default: + return PICOPAM_NA; + break; + } + return PICO_ERR_OTHER; +}/*pam_adapter_forward_step*/ + +/** + * performs the backward step of the PAM adapter + * @param this : pointer to PAM PU sub object pointer + * @return PICO_OK : backward step complete + * @return PICO_ERR_OTHER : errors on retrieving the PU pointer + * @remarks derived in some parts from the pam forward code + * @callgraph + * @callergraph + */ +static pico_status_t pam_adapter_backward_step( + register picodata_ProcessingUnit this) +{ + register pam_subobj_t * pam; + picoos_uint8 nProcessed; + picoos_uint16 nSyll; + + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + pam = (pam_subobj_t *) this->subObj; + + /*Resets the processors for the backward step*/ + pam_reset_processors_back(this); + /*Do the backward step*/ + nSyll = pam->nCurrSyllable; + while (pam->nCurrSyllable >= 0) { + nProcessed = 0; + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[P2] == 1) { + /*primary boundary*/ + pam_process_event(this, PICOPAM_EVENT_P_BOUND, PICOPAM_DIR_BACK); + pam->nCurrSyllable--; + nProcessed = 1; + } + if ((nProcessed == 0) + && (pam->sSyllFeats[pam->nCurrSyllable].phoneV[P3] == 1)) { + /*secondary boundary*/ + pam_process_event(this, PICOPAM_EVENT_S_BOUND, PICOPAM_DIR_BACK); + pam_process_event(this, PICOPAM_EVENT_SYLL, PICOPAM_DIR_BACK); + pam->nCurrSyllable--; + nProcessed = 1; + } + if ((nProcessed == 0) + && (pam->sSyllFeats[pam->nCurrSyllable].phoneV[P4] == 1)) { + /*word boundary*/ + pam_process_event(this, PICOPAM_EVENT_W_BOUND, PICOPAM_DIR_BACK); + pam_process_event(this, PICOPAM_EVENT_SYLL, PICOPAM_DIR_BACK); + pam->nCurrSyllable--; + nProcessed = 1; + } + if (nProcessed == 0) { + /*non boundaried syllable*/ + pam_process_event(this, PICOPAM_EVENT_SYLL, PICOPAM_DIR_BACK); + pam->nCurrSyllable--; + nProcessed = 0; + } + }/*end while (pam->nCurrSyllable>=0)*/ + /*reset syllpointer to original value*/ + pam->nCurrSyllable = nSyll; + /*Perform pause processing*/ + pam_adapter_do_pauses(this); + pam->nCurrSyllable = 0; + pam->nSyllPhoneme = 0; + + return PICO_OK; +}/*pam_adapter_backward_step*/ + +/** + * processes a pause (silence) syllable after backward processing + * @param this : pointer to PAM PU sub object pointer : processes a pause (silence) syllable after backward processing + * @return PICO_OK : backward step complete + * @return PICO_ERR_OTHER : errors on retrieving the PU pointer + * @remarks pam->nCurrSyllable should point to a pause item + * @remarks this function should be called after backward processing + * @remarks this function corresponds to initializing silence phonemes with + * @remarks values derived from previous or following syllables + * @callgraph + * @callergraph + */ +static pico_status_t pam_do_pause(register picodata_ProcessingUnit this) +{ + picoos_uint16 syllCurr; + pam_subobj_t *pam; + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + pam = (pam_subobj_t *) this->subObj; + syllCurr = pam->nCurrSyllable; + + /*processor for all features that can be inherited from previous syll (or word/phrase)*/ + if (pam->nCurrSyllable > 0) { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[A3] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[B3]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B8] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[B8]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B10] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[B10]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B12] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[B12]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B14] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[B14]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B17] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[B17]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B19] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[B19]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B20] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[B20]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B21] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[B21]; + + pam->sSyllFeats[pam->nCurrSyllable].phoneV[D2] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[E2]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[G1] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[H1]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[G2] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[H2]; + + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E5] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[E5]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E7] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[E7]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E9] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[E9]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E11] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[E11]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E12] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[E12]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E13] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[E13]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[E13] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[E13]; + + pam->sSyllFeats[pam->nCurrSyllable].phoneV[H1] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[H1]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[H2] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[H2]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[H3] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[H3]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[H4] + = pam->sSyllFeats[pam->nCurrSyllable - 1].phoneV[H4]; + + } else { + pam->sSyllFeats[pam->nCurrSyllable].phoneV[A3] + =pam->sSyllFeats[pam->nCurrSyllable].phoneV[B8] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[B10] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[B12] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[B14] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[B17] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[B19] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[B20] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[B21] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[E5] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[E9] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[E11] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[E12] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[H1] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[H2] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[H3] + = 0; + + /*init values different from 0*/ + pam->sSyllFeats[pam->nCurrSyllable].phoneV[H4] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[J3]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[H5] = PICOPAM_p; + + } + + /*processor for all features that can be inherited from next syll (or word/phrase)*/ + if (pam->nCurrSyllable < pam->nTotalSyllables - 1) { + /*non last syllable*/ + pam->sSyllFeats[pam->nCurrSyllable].phoneV[C3] + = pam->sSyllFeats[pam->nCurrSyllable + 1].phoneV[B3]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[F2] + = pam->sSyllFeats[pam->nCurrSyllable + 1].phoneV[E2]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[I1] + = pam->sSyllFeats[pam->nCurrSyllable + 1].phoneV[H1]; + pam->sSyllFeats[pam->nCurrSyllable].phoneV[I2] + = pam->sSyllFeats[pam->nCurrSyllable + 1].phoneV[H2]; + } else { + /*last syllable*/ + pam->sSyllFeats[pam->nCurrSyllable].phoneV[C3] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[F2] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[I1] + = pam->sSyllFeats[pam->nCurrSyllable].phoneV[I2] + = 0; + } + + /*Other fixed values derived from de-facto standard*/ + pam->sSyllFeats[pam->nCurrSyllable].phoneV[B18] = 0; + + return PICO_OK; +}/*pam_do_pause*/ + +/** + * performs the initialization of pause "syllables" + * @param this : pointer to PAM PU sub object pointer : processes a pause (silence) syllable after backward processing + * @return PICO_OK : pause processing successful + * @return PICO_ERR_OTHER : errors on retrieving the PU pointer + * @callgraph + * @callergraph + */ +static pico_status_t pam_adapter_do_pauses(register picodata_ProcessingUnit this) +{ + register pam_subobj_t * pam; + picoos_uint16 nSyll; + + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + pam = (pam_subobj_t *) this->subObj; + + /*Do the pause processing*/ + nSyll = pam->nCurrSyllable; + while (pam->nCurrSyllable >= 0) { + if (pam->sSyllFeats[pam->nCurrSyllable].phoneV[P2] == 1) { + /*pause processing*/ + pam_do_pause(this); + } + pam->nCurrSyllable--; + }/*end while (pam->nCurrSyllable>=0)*/ + /*reset syllpointer to original value*/ + pam->nCurrSyllable = nSyll; + return PICOPAM_READY; +}/*pam_adapter_do_pauses*/ + +#ifdef __cplusplus +} +#endif + +/* picopam.c end */ diff --git a/pico/lib/picopam.h b/pico/lib/picopam.h new file mode 100644 index 0000000..18f7730 --- /dev/null +++ b/pico/lib/picopam.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picopam.h + * + * Phonetic to Acoustic Mapping PU - Header file + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ +/** + * @addtogroup picopam + + * Phonetic to acoustic mapping module \n + * + * This module is responsible for mapping the phonetic domain features generated from text analysis + * into parametric representations suitable for signal generation. As such it is the interface + * between text analysis and signal generation + * + * Most the processing of PAM is logically splittable as follows + * - building a suitable symbolic feature vector set for the sentence + * - Feeding Decision Trees with the symbolic seqence vector set + * - Colecting the parametric output of the Decision trees into suitable items to be sent to following PU's + * + * To perform the decision tree feeding and output collection the PU uses an internal buffer. This + * buffer is used several times with different meanings. + * - While building the symbolic feature vector set for the sentence this data structure stores syllable relevant data. + * The corresponding phonetic data is stored outside as a single string of phonetic id's for all the sentence. + * - While feeding the decision trees the data structure is used to represent data for phonemes of the syllable + * - Addiotional data strucures are mantained to temporarily store items not pertaining to the PAM processing, for later resynchronization + * + * A quite detailed description of PAM processing is in the Know How section of the repository. + */ + +#ifndef PICOPAM_H_ +#define PICOPAM_H_ + +#include "picodata.h" +#include "picokdt.h" +#include "picokpdf.h" +#include "picoktab.h" +#include "picokdbg.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +/*------------------------------------------------------------------ +Service routines +------------------------------------------------------------------*/ +picodata_ProcessingUnit picopam_newPamUnit( + picoos_MemoryManager mm, picoos_Common common, + picodata_CharBuffer cbIn, picodata_CharBuffer cbOut, + picorsrc_Voice voice); + +#ifdef __cplusplus +} +#endif +#endif /*PICOPAM_H_*/ diff --git a/pico/lib/picopltf.h b/pico/lib/picopltf.h new file mode 100644 index 0000000..9b7cffd --- /dev/null +++ b/pico/lib/picopltf.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picopltf.h + * + * Header file (only) to define platform symbols. + * + * Refer to http://predef.sourceforge.net/ for a comprehensive list + * of pre-defined C/C++ compiler macros. + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + */ + +#if !defined(__PICOPLTF_H__) +#define __PICOPLTF_H__ + +#define ENDIANNESS_BIG 1 +#define ENDIANNESS_LITTLE 2 + +/* * platform identifiers ***/ +#define PICO_Windows 1 /* Windows */ +#define PICO_MacOSX 5 /* Macintosh OS X */ +#define PICO_Linux 7 /* Linux */ + +#define PICO_GENERIC 99 /* Generic */ + +/* * definition of current platform ***/ +#if !defined(PICO_PLATFORM) +#if defined(_WIN32) +#define PICO_PLATFORM PICO_Windows +#elif defined(__APPLE__) && defined(__MACH__) +#define PICO_PLATFORM PICO_MacOSX +#elif defined(linux) || defined(__linux__) || defined(__linux) +#define PICO_PLATFORM PICO_Linux +#else +#define PICO_PLATFORM PICO_GENERIC +#endif +#endif /* !defined(PICO_PLATFORM) */ + + +/* * symbol PICO_PLATFORM_STRING to define platform as string ***/ +#if (PICO_PLATFORM == PICO_Windows) +#define PICO_PLATFORM_STRING "Windows" +#elif (PICO_PLATFORM == PICO_MacOSX) +#define PICO_PLATFORM_STRING "MacOSX" +#elif (PICO_PLATFORM == PICO_Linux) +#define PICO_PLATFORM_STRING "Linux" +#elif (PICO_PLATFORM == PICO_GENERIC) +#define PICO_PLATFORM_STRING "UnknownPlatform" +#endif + +#if defined(__FreeBSD__) +#define __BYTE_ORDER _BYTE_ORDER +#define __BIG_ENDIAN _BIG_ENDIAN +#include +#else +#include +#endif + +#if __BYTE_ORDER == __BIG_ENDIAN +#define PICO_ENDIANNESS ENDIANNESS_BIG +#else +#define PICO_ENDIANNESS ENDIANNESS_LITTLE +#endif + +#endif /* !defined(__PICOPLTF_H__) */ diff --git a/pico/lib/picopr.c b/pico/lib/picopr.c new file mode 100644 index 0000000..519a2f6 --- /dev/null +++ b/pico/lib/picopr.c @@ -0,0 +1,3555 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picopr.c + * + * text preprocessor + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include "picodefs.h" +#include "picoos.h" +#include "picobase.h" +#include "picodbg.h" +#include "picodata.h" +#include "picokpr.h" +#include "picopr.h" +#include "picoktab.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* *****************************************************************************/ +/* constants */ +/* *****************************************************************************/ + +#define PR_TRACE_MEM FALSE +#define PR_TRACE_MAX_MEM FALSE +#define PR_TRACE_PATHCOST TRUE + +#define PR_WORK_MEM_SIZE 10000 +#define PR_DYN_MEM_SIZE 7000 + +#define PR_ENABLED TRUE + +#define PR_MAX_NR_ITERATIONS 1000; + +#define SPEC_CHAR "\\/" + +#define PICO_ERR_CONTEXT_NOT_FOUND PICO_ERR_OTHER +#define PICO_ERR_MAX_PREPROC_PATH_LEN_REACHED PICO_ERR_OTHER + +#define IN_BUF_SIZE 255 +#define OUT_BUF_SIZE IN_BUF_SIZE + 3 * PICODATA_ITEM_HEADSIZE + 3 + +#define PR_MAX_NR_PREPROC (1 + PICOKNOW_MAX_NUM_UTPP) + +#define PR_MAX_PATH_LEN 130 +#define PR_MAX_DATA_LEN IN_BUF_SIZE +#define PR_MAX_DATA_LEN_Z PR_MAX_DATA_LEN + 1 /* all strings in picopr should use this constant + to ensure zero termination */ +#define PR_COST_INIT 100000 +#define PR_COST 10 +#define PR_EOL '\n' + +/* Bit mask constants for token sets with parameters */ +#define PR_TSE_MASK_OUT (1<pr_DynMem. Dynamic memory has + to be deallocated again with pr_DEALLOCATE. + Working memory is allocated in pr_subobj_t->pr_WorkMem. Working memory is stack + based and may not to be deallocated with pr_DEALLOCATE, but with pr_resetMemState + to a state previously saved with pr_getMemState. +*/ + +static void pr_ALLOCATE (picodata_ProcessingUnit this, pr_MemTypes mType, void * * adr, unsigned int byteSize) + /* allocates 'byteSize' bytes in the memery partition given by 'mType' */ +{ + pr_subobj_t * pr = (pr_subobj_t *) this->subObj; + picoos_int32 incrUsedBytes, prevmaxDynMemSize; + + if (mType == pr_WorkMem) { + if ((pr->workMemTop + byteSize) < PR_WORK_MEM_SIZE) { + (*adr) = (void *)(&(pr->pr_WorkMem[pr->workMemTop])); + byteSize = ((byteSize + PICOOS_ALIGN_SIZE - 1) / PICOOS_ALIGN_SIZE) * PICOOS_ALIGN_SIZE; + pr->workMemTop += byteSize; +#if PR_TRACE_MEM + PICODBG_INFO(("pr_WorkMem: +%u, tot:%i of %i", byteSize, pr->workMemTop, PR_WORK_MEM_SIZE)); +#endif + + if (pr->workMemTop > pr->maxWorkMemTop) { + pr->maxWorkMemTop = pr->workMemTop; +#if PR_TRACE_MAX_MEM + PICODBG_INFO(("new max pr_WorkMem: %i of %i", pr->workMemTop, PR_WORK_MEM_SIZE)); +#endif + } + } + else { + (*adr) = NULL; + PICODBG_ERROR(("pr out of working memory")); + picoos_emRaiseException(this->common->em, PICO_EXC_OUT_OF_MEM, (picoos_char *)"pr out of dynamic memory", (picoos_char *)""); + pr->outOfMemory = TRUE; + } + } + else if (mType == pr_DynMem) { + (*adr) = picoos_allocate(pr->dynMemMM, byteSize); + if ((*adr) != NULL) { + prevmaxDynMemSize = pr->maxDynMemSize; + picoos_getMemUsage(pr->dynMemMM, 1, &pr->dynMemSize, &incrUsedBytes, &pr->maxDynMemSize); +#if PR_TRACE_MEM + PICODBG_INFO(("pr_DynMem : +%i, tot:%i of %i", incrUsedBytes, pr->dynMemSize, PR_DYN_MEM_SIZE)); +#endif + +#if PR_TRACE_MAX_MEM + if (pr->maxDynMemSize > prevmaxDynMemSize) { + PICODBG_INFO(("new max pr_DynMem : %i of %i", pr->maxDynMemSize, PR_DYN_MEM_SIZE)); + } +#endif + } + else { + PICODBG_ERROR(("pr out of dynamic memory")); + picoos_emRaiseException(this->common->em, PICO_EXC_OUT_OF_MEM, (picoos_char *)"pr out of dynamic memory", (picoos_char *)""); + pr->outOfMemory = TRUE; + } + } + else { + (*adr) = NULL; + } +} + + +static void pr_DEALLOCATE (picodata_ProcessingUnit this, pr_MemTypes mType, void * * adr) +{ + pr_subobj_t * pr = (pr_subobj_t *) this->subObj; + picoos_int32 incrUsedBytes; + if (mType == pr_WorkMem) { + PICODBG_INFO(("not possible; use pr_resetMemState instead")); + } + else if (mType == pr_DynMem) { + picoos_deallocate(pr->dynMemMM, &(*adr)); + picoos_getMemUsage(pr->dynMemMM, 1, &pr->dynMemSize, &incrUsedBytes, &pr->maxDynMemSize); +#if PR_TRACE_MEM + PICODBG_INFO(("pr_DynMem : %i, tot:%i of %i: adr: %u", incrUsedBytes, pr->dynMemSize, PR_DYN_MEM_SIZE, *adr)); +#endif + } + else { + (*adr) = NULL; + } +} + + +static void pr_getMemState(picodata_ProcessingUnit this, pr_MemTypes mType, picoos_uint32 *lmemState) +{ + pr_subobj_t * pr = (pr_subobj_t *) this->subObj; + mType = mType; /* avoid warning "var not used in this function"*/ + *lmemState = pr->workMemTop; +} + + +static void pr_resetMemState(picodata_ProcessingUnit this, pr_MemTypes mType, picoos_uint32 lmemState) +{ + pr_subobj_t * pr = (pr_subobj_t *) this->subObj; + +#if PR_TRACE_MEM + PICODBG_INFO(("pr_WorkMem: -%i, tot:%i of %i", pr->workMemTop-lmemState, lmemState, PR_WORK_MEM_SIZE)); +#endif + mType = mType; /* avoid warning "var not used in this function"*/ + pr->workMemTop = lmemState; +} + + +/* *****************************************************************************/ +/* string operations */ + +static picoos_int32 pr_strlen(const picoos_uchar * str) +{ + picoos_int32 i; + + i=0; + while ((i= length) { + return length; + } else { + i = pos + len; + while (i < length) { + str[pos] = str[i]; + i++; + pos++; + } + str[pos] = 0; + return pos; + } +} + + +static picoos_bool pr_strEqual(picoos_uchar * str1, picoos_uchar * str2) +{ + return (picoos_strcmp((picoos_char *)str1, (picoos_char *)str2) == 0); +} + + +static void pr_int_to_string(picoos_int32 n, picoos_uchar * str, picoos_int32 maxstrlen) +{ + picoos_int32 i, len; + picoos_bool negative=FALSE; + + len = 0; + str[0] = 0; + if (n<0) { + negative = TRUE; + n = -n; + len++; + } + i = n; + + while (i>0) { + i = i / 10; + len++; + } + + if (len0) && (len>0)) { + len--; + str[len] = i % 10 + '0'; + i = i / 10; + } + if (negative) { + len--; + str[len] = '-'; + } + } +} +/* *****************************************************************************/ + +static void pr_firstLetterToLowerCase (const picoos_uchar src[], picoos_uchar dest[]) +{ + + picoos_int32 i; + picoos_int32 j; + picoos_int32 l; + picoos_bool done; + + i = 0; + j = 0; + l = picobase_det_utf8_length(src[0]); + while ((i < l) && (j < PR_MAX_DATA_LEN)) { + dest[j] = src[i]; + i++; + j++; + } + if (j < PR_MAX_DATA_LEN) { + dest[j] = 0; + } + picobase_lowercase_utf8_str(dest, (picoos_char*)dest, PR_MAX_DATA_LEN, &done); + j = picobase_det_utf8_length(dest[0]); + l = pr_strlen(src); + while ((i < l) && (j < PR_MAX_DATA_LEN)) { + dest[j] = src[i]; + i++; + j++; + } + dest[j] = 0; +} + + +static picoos_int32 tok_tokenDigitStrToInt (picodata_ProcessingUnit this, pr_subobj_t * pr, picoos_uchar stokenStr[]) +{ + picoos_uint32 i; + picoos_uint32 l; + picoos_int32 id; + picoos_int32 val; + picoos_uint32 n; + picobase_utf8char utf8char; + + val = 0; + i = 0; + l = pr_strlen(stokenStr); + while (i < l) { + picobase_get_next_utf8char(stokenStr, PR_MAX_DATA_LEN, & i, utf8char); + id = picoktab_graphOffset(pr->graphs, utf8char); + if (id > 0) { + if (picoktab_getIntPropValue(pr->graphs, id, &n)) { + val = (10 * val) + n; + } else { + val = ((10 * val) + (int)((int)utf8char[0] - (int)'0')); + } + } else if ((utf8char[0] >= '0') && (utf8char[0] <= '9')) { + val = 10 * val + ((int)utf8char[0] - (int)'0'); + } + } + return val; +} + + +static picoos_bool pr_isLatinNumber (picoos_uchar str[], picoos_int32 * val) +{ + + picoos_uint32 li; + picoos_uint32 llen; + picoos_uchar lact; + picoos_uchar lnext; + picoos_uchar lprev; + picoos_uchar llatinI; + picoos_uchar llatinV; + picoos_uchar llatinX; + picoos_uchar llatinL; + picoos_uchar llatinC; + picoos_uchar llatinD; + picoos_uchar llatinM; + picoos_int32 lseq; + picobase_utf8char utf8; + + *val = 0; + llen = picobase_utf8_length(str, PR_MAX_DATA_LEN); + if (llen > 0) { + li = 0; + picobase_get_next_utf8char(str, PR_MAX_DATA_LEN, & li,utf8); + if (picobase_is_utf8_uppercase(utf8, PICOBASE_UTF8_MAXLEN)) { + llatinI = 'I'; + llatinV = 'V'; + llatinX = 'X'; + llatinL = 'L'; + llatinC = 'C'; + llatinD = 'D'; + llatinM = 'M'; + } else { + llatinI = 'i'; + llatinV = 'v'; + llatinX = 'x'; + llatinL = 'l'; + llatinC = 'c'; + llatinD = 'd'; + llatinM = 'm'; + } + lseq = 1000; + li = 0; + while (li < llen) { + if (li > 0) { + lprev = str[li - 1]; + } else { + lprev = 0; + } + lact = str[li]; + if (li < (llen - 1)) { + lnext = str[li + 1]; + } else { + lnext = 0; + } + if ((lseq > 1) && (lact == llatinI)) { + if ((lprev != lact) && (lseq >= 4)) { + if (lnext == llatinV) { + *val = *val + 4; + li++; + lseq = 1; + } else if (lnext == llatinX) { + *val = *val + 9; + li++; + lseq = 1; + } else { + *val = *val + 1; + lseq = 3; + } + } else { + *val = *val + 1; + lseq = lseq - 1; + } + } else if ((lseq > 5) && (lact == llatinV)) { + *val = *val + 5; + lseq = 5; + } else if ((lseq > 10) && (lact == llatinX)) { + if ((lprev != lact) && (lseq >= 40)) { + if (lnext == llatinL) { + *val = *val + 40; + li++; + lseq = 10; + } else if (lnext == llatinC) { + *val = *val + 90; + li++; + lseq = 10; + } else { + *val = *val + 10; + lseq = 30; + } + } else { + *val = *val + 10; + lseq = lseq - 10; + } + } else if ((lseq > 50) && (lact == llatinL)) { + *val = *val + 50; + lseq = 50; + } else if ((lseq > 100) && (lact == llatinC)) { + if ((lprev != lact) && (lseq >= 400)) { + if (lnext == llatinD) { + *val = *val + 400; + li++; + lseq = 100; + } else if (lnext == llatinM) { + *val = *val + 900; + li++; + lseq = 100; + } else { + *val = *val + 100; + lseq = 300; + } + } else { + *val = *val + 100; + lseq = lseq - 100; + } + } else if ((lseq > 500) && (lact == llatinD)) { + *val = *val + 500; + lseq = 500; + } else if ((lseq >= 1000) && (lact == llatinM)) { + *val = *val + 1000; + } else { + return FALSE; + } + li++; + } + } + return TRUE; +} + + +static picoos_bool pr_isSUC (picoos_uchar str[]) +{ + + picoos_int32 li; + picoos_bool lis; + picobase_utf8char lutf; + picoos_int32 lj; + picoos_int32 ll; + picoos_bool luc; + + li = 0; + lis = TRUE; + luc = TRUE; + while (lis && (li < PR_MAX_DATA_LEN) && (str[li] != 0)) { + lj = 0; + ll = picobase_det_utf8_length(str[li]); + while (lj < ll) { + lutf[lj] = str[li]; + lj++; + li++; + } + lutf[lj] = 0; + if (luc) { + lis = lis && picobase_is_utf8_uppercase(lutf,PICOBASE_UTF8_MAXLEN+1); + } else { + lis = lis && picobase_is_utf8_lowercase(lutf,PICOBASE_UTF8_MAXLEN+1); + } + luc = FALSE; + } + return lis; +} + +/* *****************************************************************************/ + +static picoos_bool pr_isCmdType (pr_ioItemPtr it, picoos_uint8 type) +{ + if ((it != NULL) && (it->head.type == PICODATA_ITEM_CMD) && (it->head.info1 == type)) { + return TRUE; + } else { + return FALSE; + } +} + + +static picoos_bool pr_isCmdInfo2 (pr_ioItemPtr it, picoos_uint8 info2) +{ + if ((it != NULL) && (it->head.type == PICODATA_ITEM_CMD) && (it->head.info2 == info2)) { + return TRUE; + } else { + return FALSE; + } +} + + +static void pr_initPathEle (struct pr_PathEle * ele) +{ + ele->rnetwork = NULL; + ele->rtok = 0; + ele->ritemid = -1; + ele->rdepth = 1; + ele->rlState = PR_LSInit; + ele->rcompare = -1; + ele->rprodname = 0; + ele->rprodprefcost = 0; +} + +/* *****************************************************************************/ + +static void pr_disposeProdList (register picodata_ProcessingUnit this, pr_ProdList * prodList) +{ + pr_ProdList p; + + while ((*prodList) != NULL) { + p = (*prodList); + (*prodList) = (*prodList)->rNext; + picoos_deallocate(this->common->mm, (void *) &p); + } +} + + +static pico_Status pr_addContext (register picodata_ProcessingUnit this, pr_subobj_t * pr, pr_ContextList * ctxList, picokpr_VarStrPtr contextNamePtr, picokpr_VarStrPtr netNamePtr, picokpr_VarStrPtr prodNamePtr) +{ + picokpr_Preproc net; + pr_ContextList ctx; + pr_ProdList prod; + int i; + picokpr_VarStrPtr strp; + picoos_int32 lprodarrlen; + + ctx = (*ctxList); + while ((ctx != NULL) && !(pr_strEqual(contextNamePtr, ctx->rContextName))) { + ctx = ctx->rNext; + } + if (ctx == NULL) { + ctx = picoos_allocate(this->common->mm, sizeof(pr_Context)); + if (ctx == NULL) { + return PICO_EXC_OUT_OF_MEM; + } + ctx->rNext = (*ctxList); + ctx->rProdList = NULL; + ctx->rContextName = contextNamePtr; + (*ctxList) = ctx; + } + i = 0; + net = pr->preproc[i]; + while ((ipreproc[i]; + } + if (net != NULL) { + i = 0; + strp = picokpr_getVarStrPtr(net, picokpr_getProdNameOfs(net, i)); + lprodarrlen = picokpr_getProdArrLen(net); + while ((i < lprodarrlen) && !(pr_strEqual(prodNamePtr, strp))) { + i++; + if (i < lprodarrlen) { + strp = picokpr_getVarStrPtr(net, picokpr_getProdNameOfs(net, i)); + } + } + if (i < lprodarrlen) { + prod = picoos_allocate(this->common->mm, sizeof(pr_Prod)); + if (prod == NULL) { + return PICO_EXC_OUT_OF_MEM; + } + prod->rNetwork = net; + prod->rProdOfs = i; + prod->rNext = ctx->rProdList; + ctx->rProdList = prod; + } + } + return PICO_OK; +} + + +static pico_Status pr_createContextList (register picodata_ProcessingUnit this) +{ + pr_subobj_t * pr = (pr_subobj_t *) this->subObj; + picokpr_VarStrPtr ctxNamePtr; + picokpr_VarStrPtr netNamePtr; + picokpr_VarStrPtr prodNamePtr; + picoos_int32 p, i, n; + pico_Status status; + + pr->ctxList = NULL; + for (p=0; ppreproc[p] != NULL) { + n = picokpr_getCtxArrLen(pr->preproc[p]); + for (i = 1; ipreproc[p], picokpr_getCtxCtxNameOfs(pr->preproc[p], i)); + netNamePtr = picokpr_getVarStrPtr(pr->preproc[p], picokpr_getCtxNetNameOfs(pr->preproc[p], i)); + prodNamePtr = picokpr_getVarStrPtr(pr->preproc[p], picokpr_getCtxProdNameOfs(pr->preproc[p], i)); + status = pr_addContext(this, pr, &pr->ctxList, ctxNamePtr,netNamePtr, prodNamePtr); + if (status != PICO_OK) { + return status; + } + } + } + } + return PICO_OK; +} + + +static void pr_disposeContextList (register picodata_ProcessingUnit this) +{ + pr_subobj_t * pr = (pr_subobj_t *) this->subObj; + pr_ContextList c; + + while (pr->ctxList != NULL) { + c = pr->ctxList; + pr->ctxList = pr->ctxList->rNext; + pr_disposeProdList(this, & c->rProdList); + picoos_deallocate(this->common->mm, (void *) &c); + } +} + + +static pr_ContextList pr_findContext (pr_ContextList contextList, picoos_uchar contextName[]) +{ + pr_ContextList context; + + context = contextList; + while ((context != NULL) && !(pr_strEqual(context->rContextName,contextName))) { + context = context->rNext; + } + return context; +} + + +static void pr_setContext (register picodata_ProcessingUnit this, pr_subobj_t * pr, picoos_uchar context[]) +{ + + pr_ContextList ctx; + + ctx = pr_findContext(pr->ctxList,context); + if (ctx != NULL) { + pr->actCtx = ctx; + pr->actCtxChanged = TRUE; + } else { + PICODBG_WARN(("context '%s' not found; no change",context)); + picoos_emRaiseWarning(this->common->em, PICO_ERR_CONTEXT_NOT_FOUND, (picoos_char*)"context '%s' not found; no change",(picoos_char*)context); + } +} + +/* *****************************************************************************/ +/* item handling routines */ + + +static picoos_uint32 pr_copyData(picoos_uint8 * dest, const picoos_uint8 * src, picoos_int32 nrBytes, picoos_bool zeroTerm) +{ + picoos_int32 i=0; + + if ((src != NULL) && (dest != NULL)) { + i = 0; + while ((inext = NULL; + item->val = 0; + item->head.len = 0; + item->strci = NULL; + item->strcis = NULL; + item->suc = FALSE; + item->alc = FALSE; + item->auc = FALSE; +} + + +static void pr_newItem (picodata_ProcessingUnit this, pr_MemTypes mType, pr_ioItemPtr * item, picoos_uint8 itemType, picoos_int32 size, picoos_bool inItem) +{ + pr_subobj_t * pr = (pr_subobj_t *) this->subObj; + + if (mType == pr_WorkMem) { + pr_ALLOCATE(this, mType, (void * *) & (*item),PR_IOITEM_MIN_SIZE+size+1); + if (pr->outOfMemory) return; + pr_initItem(this, *item); + } + else if ((mType == pr_DynMem) && inItem) { + pr_ALLOCATE(this, mType, (void * *) & (*item), PR_IOITEM_MIN_SIZE+3*size+3); + if (pr->outOfMemory) return; + pr_initItem(this, *item); + if (itemType == PICODATA_ITEM_TOKEN) { + (*item)->strci = &((*item)->data[size+1]); + (*item)->strcis = &((*item)->data[2*size+2]); + (*item)->strci[0] = 0; + (*item)->strcis[0] = 0; + } + } + else if ((mType == pr_DynMem) && !inItem) { + pr_ALLOCATE(this, mType, (void * *) & (*item), PR_IOITEM_MIN_SIZE+size+1); + if (pr->outOfMemory) return; + pr_initItem(this, *item); + } + + (*item)->data[0] = 0; +} + + +static void pr_copyItemContent (picodata_ProcessingUnit this, pr_ioItem * inItem, pr_ioItem * outItem) +{ + if (outItem != NULL) { + outItem->next = inItem->next; + outItem->val = inItem->val; + outItem->head = inItem->head; + outItem->suc = inItem->suc; + outItem->alc = inItem->alc; + outItem->auc = inItem->auc; + if (inItem->head.len > 0 ) { + pr_copyData(outItem->data, inItem->data, inItem->head.len, /*zeroTerm*/TRUE); + pr_copyData(outItem->strci, inItem->strci, inItem->head.len, /*zeroTerm*/TRUE); + pr_copyData(outItem->strcis, inItem->strcis, inItem->head.len, /*zeroTerm*/TRUE); + } + } +} + + +static void pr_copyItem (picodata_ProcessingUnit this, pr_MemTypes mType, pr_ioItemPtr inItem, pr_ioItemPtr * outItem) +{ + pr_subobj_t * pr = (pr_subobj_t *) this->subObj; + + if (inItem != NULL) { + pr_newItem(this, mType,& (*outItem), inItem->head.type, inItem->head.len, FALSE); + if (pr->outOfMemory) return; + pr_copyItemContent(this, inItem, *outItem); + } + else { + outItem = NULL; + } +} + + +static void pr_startItemList (pr_ioItemPtr * firstItem, pr_ioItemPtr * lastItem) +{ + *firstItem = NULL; + *lastItem = NULL; +} + + +static void pr_appendItem (picodata_ProcessingUnit this, pr_ioItemPtr * firstItem, pr_ioItemPtr * lastItem, pr_ioItemPtr item) +{ + if (item != NULL) { + item->next = NULL; + if ((*lastItem) == NULL) { + *firstItem = item; + } else { + (*lastItem)->next = item; + } + (*lastItem) = item; + } +} + + +static void pr_disposeItem (picodata_ProcessingUnit this, pr_ioItemPtr * item) +{ + if ((*item) != NULL) { + pr_DEALLOCATE(this, pr_DynMem, (void * *) & (*item)); + } +} + + +static void pr_putItem (picodata_ProcessingUnit this, pr_subobj_t * pr, + pr_ioItemPtr * first, pr_ioItemPtr * last, + picoos_uint8 itemType, picoos_uint8 info1, picoos_uint8 info2, + picoos_uint16 val, + picoos_uchar str[]) +{ + picoos_int32 i; + pr_ioItemPtr item; + + pr->tmpItem.next = NULL; + pr->tmpItem.val = 0; + pr->tmpItem.head.type = itemType; + pr->tmpItem.head.info1 = info1; + pr->tmpItem.head.info2 = info2; + + pr_initItem(this, &pr->tmpItem); + switch (itemType) { + case PICODATA_ITEM_CMD: + switch (info1) { + case PICODATA_ITEMINFO1_CMD_CONTEXT: + case PICODATA_ITEMINFO1_CMD_VOICE: + case PICODATA_ITEMINFO1_CMD_MARKER: + case PICODATA_ITEMINFO1_CMD_PLAY: + case PICODATA_ITEMINFO1_CMD_SAVE: + case PICODATA_ITEMINFO1_CMD_UNSAVE: + case PICODATA_ITEMINFO1_CMD_PROSDOMAIN: + pr->tmpItem.head.len = picoos_strlen((picoos_char*)str); + for (i=0; itmpItem.head.len; i++) { + pr->tmpItem.data[i] = str[i]; + } + pr_copyItem(this, pr_WorkMem, &pr->tmpItem, & item); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last),item); + break; + case PICODATA_ITEMINFO1_CMD_IGNSIG: + case PICODATA_ITEMINFO1_CMD_IGNORE: + case PICODATA_ITEMINFO1_CMD_FLUSH: + pr->tmpItem.head.len = 0; + pr_copyItem(this, pr_WorkMem, &pr->tmpItem, & item); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last),item); + break; + case PICODATA_ITEMINFO1_CMD_SPEED: + case PICODATA_ITEMINFO1_CMD_PITCH: + case PICODATA_ITEMINFO1_CMD_VOLUME: + case PICODATA_ITEMINFO1_CMD_SPELL: + case PICODATA_ITEMINFO1_CMD_SIL: + pr->tmpItem.head.len = 2; + pr->tmpItem.data[0] = val % 256; + pr->tmpItem.data[1] = val / 256; + pr_copyItem(this, pr_WorkMem, &pr->tmpItem, & item); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last),item); + break; + case PICODATA_ITEMINFO1_CMD_PHONEME: + PICODBG_WARN(("phoneme command not yet implemented")); + break; + default: + PICODBG_WARN(("pr_putItem: unknown command type")); + } + break; + case PICODATA_ITEM_TOKEN: + pr->tmpItem.head.len = picoos_strlen((picoos_char*)str); + for (i=0; itmpItem.head.len; i++) { + pr->tmpItem.data[i] = str[i]; + } + pr_copyItem(this, pr_WorkMem, &pr->tmpItem, & item); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last),item); + break; + default: + PICODBG_WARN(("pr_putItem: unknown item type")); + } +} + + +static void pr_appendItemToOutItemList (picodata_ProcessingUnit this, pr_subobj_t * pr, + pr_ioItemPtr * firstItem, pr_ioItemPtr * lastItem, pr_ioItemPtr item) +{ + pr_ioItemPtr litem; + picoos_int32 li; + picoos_int32 li2; + picoos_int32 lid; + picoos_int32 ln; + picoos_int32 ln2; + picoos_uint8 ltype; + picoos_int8 lsubtype; + picoos_uchar lstr[10]; + picoos_bool ldone; + + item->next = NULL; + if (((pr->spellMode != 0) && (item->head.type == PICODATA_ITEM_TOKEN) && (item->head.info1 != PICODATA_ITEMINFO1_TOKTYPE_SPACE))) { + li = 0; + ln = pr_strlen(item->data); + while (li < ln) { + ln2 = picobase_det_utf8_length(item->data[li]); + for (li2 = 0; li2data[li]; + li++; + } + lstr[ln2] = 0; + lid = picoktab_graphOffset(pr->graphs, lstr); + if ((lid > 0) && picoktab_getIntPropTokenType(pr->graphs, lid, <ype) && + ((ltype == PICODATA_ITEMINFO1_TOKTYPE_LETTERV) /*|| (ltype == PICODATA_ITEMINFO1_TOKTYPE_DIGIT)*/)) { + ln2 = pr_strcat(lstr,(picoos_uchar*)SPEC_CHAR); + picoktab_getIntPropTokenSubType(pr->graphs,lid, &lsubtype); + } + else { + ltype = PICODATA_ITEMINFO1_TOKTYPE_UNDEFINED; + lsubtype = -(1); + } + pr_newItem(this, pr_DynMem,& litem, PICODATA_ITEM_TOKEN, ln2, /*inItem*/FALSE); + if (pr->outOfMemory) return; + litem->head.type = PICODATA_ITEM_TOKEN; + litem->head.info1 = item->head.info1; + litem->head.info2 = item->head.info2; + pr_strcpy(litem->data, lstr); + litem->data[ln2] = 0; + litem->head.len = ln2; + if (litem->head.info1 == PICODATA_ITEMINFO1_TOKTYPE_DIGIT) { + litem->val = tok_tokenDigitStrToInt(this, pr, litem->data); + } else { + litem->val = 0; + } + picobase_lowercase_utf8_str(litem->data,litem->strci,PR_MAX_DATA_LEN, &ldone); + pr_firstLetterToLowerCase(litem->data,litem->strcis); + litem->alc = picobase_is_utf8_lowercase(litem->data,PR_MAX_DATA_LEN); + litem->auc = picobase_is_utf8_uppercase(litem->data,PR_MAX_DATA_LEN); + litem->suc = pr_isSUC(litem->data); + + pr_appendItem(this, firstItem, lastItem, litem); + if (pr->spellMode == PR_SPELL_WITH_SENTENCE_BREAK) { + pr_newItem(this, pr_DynMem,& litem, PICODATA_ITEM_TOKEN, 2, /*inItem*/FALSE); + if (pr->outOfMemory) return; + litem->head.type = PICODATA_ITEM_TOKEN; + litem->head.info1 = PICODATA_ITEMINFO1_TOKTYPE_CHAR; + litem->head.info2 = -1; + litem->head.len = 1; + litem->data[0] = ','; + litem->data[1] = 0; + litem->strci[0] = ','; + litem->strci[1] = 0; + litem->strcis[0] = ','; + litem->strcis[1] = 0; + litem->val = 0; + pr_appendItem(this, firstItem, lastItem, litem); + } else if (pr->spellMode == PR_SPELL_WITH_SENTENCE_BREAK) { + pr_newItem(this, pr_DynMem,& litem, PICODATA_ITEM_CMD, 0, /*inItem*/FALSE); + if (pr->outOfMemory) return; + litem->head.type = PICODATA_ITEM_CMD; + litem->head.info1 = PICODATA_ITEMINFO1_CMD_FLUSH; + litem->head.info2 = PICODATA_ITEMINFO2_NA; + litem->head.len = 0; + pr_appendItem(this, firstItem, lastItem,litem); + } else if (pr->spellMode > 0) { + pr_newItem(this, pr_DynMem,& litem, PICODATA_ITEM_CMD, 2, /*inItem*/FALSE); + if (pr->outOfMemory) return; + litem->head.type = PICODATA_ITEM_CMD; + litem->head.info1 = PICODATA_ITEMINFO1_CMD_SIL; + litem->head.info2 = PICODATA_ITEMINFO2_NA; + litem->head.len = 2; + litem->data[0] = pr->spellMode % 256; + litem->data[1] = pr->spellMode / 256; + pr_appendItem(this, firstItem, lastItem, litem); + } + } + pr_disposeItem(this, & item); + } else if (pr_isCmdType(item, PICODATA_ITEMINFO1_CMD_SPELL) && pr_isCmdInfo2(item, PICODATA_ITEMINFO2_CMD_START)) { + pr->spellMode = item->data[0]+256*item->data[1]; + pr_disposeItem(this, & item); + } else if (pr_isCmdType(item, PICODATA_ITEMINFO1_CMD_SPELL) && pr_isCmdInfo2(item, PICODATA_ITEMINFO2_CMD_END)) { + pr->spellMode = 0; + pr_disposeItem(this, & item); + } else { + pr_appendItem(this, firstItem,lastItem,item); + } +} + + +/* *****************************************************************************/ + +static pr_OutItemVarPtr pr_findVariable (pr_OutItemVarPtr vars, picoos_int32 id) +{ + while ((vars != NULL) && (vars->id != id)) { + vars = vars->next; + } + if ((vars != NULL)) { + return vars; + } else { + return NULL; + } +} + + +static void pr_genCommands (picodata_ProcessingUnit this, pr_subobj_t * pr, + picokpr_Preproc network, picokpr_OutItemArrOffset outitem, pr_OutItemVarPtr vars, pr_ioItemPtr * first, pr_ioItemPtr * last) +{ + + pr_ioItemPtr litem; + pr_OutItemVarPtr lvar; + picoos_uint8 lcmd; + picoos_uint8 linfo2; + picoos_bool ldone; +#if 0 + picoos_int32 lphontype; +#endif + picokpr_VarStrPtr lstrp; + picoos_int32 lnum; + pr_ioItemPtr lf; + pr_ioItemPtr ll; + picoos_int32 lf0beg; + picoos_int32 lf0end; + ShortStrParam lxfadebeg; + ShortStrParam lxfadeend; + picoos_bool lout; + picoos_int32 ltype; + picoos_int32 argOfs; + picoos_int32 nextOfs; + picoos_int32 nextOfs2; + picoos_int32 nextOfs3; + picoos_int32 nextOfs4; + picoos_uchar alphabet[32]; + + lcmd = 0; + lnum = 0; + litem = NULL; + ltype = picokpr_getOutItemType(network, outitem); + switch (ltype) { + case PR_OIgnore: + if (picokpr_getOutItemVal(network, outitem) == 0) { + pr_putItem(this, pr, & (*first),& (*last),PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_IGNORE,PICODATA_ITEMINFO2_CMD_START,0,(picoos_uchar*)""); + } else { + pr_putItem(this, pr, & (*first),& (*last),PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_IGNORE,PICODATA_ITEMINFO2_CMD_END,0,(picoos_uchar*)""); + } + break; + case PR_OPitch: case PR_OSpeed: case PR_OVolume: + switch (ltype) { + case PR_OPitch: + lcmd = PICODATA_ITEMINFO1_CMD_PITCH; + lnum = PICO_PITCH_DEFAULT; + break; + case PR_OSpeed: + lcmd = PICODATA_ITEMINFO1_CMD_SPEED; + lnum = PICO_SPEED_DEFAULT; + break; + case PR_OVolume: + lcmd = PICODATA_ITEMINFO1_CMD_VOLUME; + lnum = PICO_VOLUME_DEFAULT; + break; + default: + break; + } + if ((picokpr_getOutItemArgOfs(network, outitem) != 0)) { + switch (picokpr_getOutItemType(network, picokpr_getOutItemArgOfs(network, outitem))) { + case PR_OVal: + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD, lcmd,PICODATA_ITEMINFO2_CMD_ABSOLUTE, picokpr_getOutItemVal(network, picokpr_getOutItemArgOfs(network, outitem)),(picoos_uchar*)""); + break; + case PR_OVar: + lvar = pr_findVariable(vars,picokpr_getOutItemVal(network, picokpr_getOutItemArgOfs(network, outitem))); + if ((lvar != NULL) && (lvar->first != NULL) && (lvar->first->head.type == PICODATA_ITEM_TOKEN)) { + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD,lcmd,PICODATA_ITEMINFO2_CMD_ABSOLUTE,picoos_atoi((picoos_char*)lvar->first->data),(picoos_uchar*)""); + } + break; + default: + pr_startItemList(& lf,& ll); + pr_getOutputItemList(this, pr, network,picokpr_getOutItemArgOfs(network, outitem),vars,& lf,& ll); + if (pr->outOfMemory) return; + if (((lf != NULL) && (lf->head.type == PICODATA_ITEM_TOKEN))) { + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD,lcmd,PICODATA_ITEMINFO2_CMD_ABSOLUTE,picoos_atoi((picoos_char*)lf->data),(picoos_uchar*)""); + } + break; + } + } else { + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD,lcmd,PICODATA_ITEMINFO2_CMD_ABSOLUTE,lnum,(picoos_uchar*)""); + } + break; + + case PR_OPhonSVOXPA: case PR_OPhonSAMPA: + if (picokpr_getOutItemArgOfs(network, outitem) != 0) { + if (ltype == PR_OPhonSVOXPA) { + picoos_strlcpy(alphabet, PICODATA_SVOXPA, sizeof(alphabet)); + } + else { + picoos_strlcpy(alphabet, PICODATA_SAMPA, sizeof(alphabet)); + } + pr_startItemList(& lf,& ll); + pr_getOutputItemList(this, pr, network,picokpr_getOutItemArgOfs(network, outitem),vars,& lf,& ll); + if (pr->outOfMemory) return; + if (lf != NULL) { + ldone = FALSE; + if (lf->head.type == PICODATA_ITEM_TOKEN) { + if (picodata_mapPAStrToPAIds(pr->transducer, this->common, pr->xsampa_parser, pr->svoxpa_parser, pr->xsampa2svoxpa_mapper, lf->data, alphabet, pr->tmpStr1, sizeof(pr->tmpStr1)-1) == PICO_OK) { + pr_putItem(this, pr, & (*first),& (*last), PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_PHONEME, + PICODATA_ITEMINFO2_CMD_START, 0, pr->tmpStr1); + ldone = TRUE; + } + else { + PICODBG_WARN(("cannot map phonetic string '%s'; synthesizeing text instead", lf->data)); + picoos_emRaiseWarning(this->common->em, PICO_ERR_OTHER,(picoos_char*)"", (picoos_char*)"cannot map phonetic string '%s'; synthesizing text instead", lf->data); + } + } + if (ldone) { + lf = lf->next; + while (lf != NULL) { + if (lf->head.type == PICODATA_ITEM_TOKEN) { + pr_putItem(this, pr, & (*first),& (*last), PICODATA_ITEM_TOKEN, PICODATA_ITEMINFO1_CMD_PHONEME, + PICODATA_ITEMINFO2_CMD_END, 0, (picoos_char *)""); + } + lf = lf->next; + } + pr_putItem(this, pr, & (*first),& (*last), PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_PHONEME, + PICODATA_ITEMINFO2_CMD_END, 0, (picoos_char *)""); + } + } + } + break; + + case PR_OSent: + pr_putItem(this, pr, & (*first),& (*last), PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_FLUSH, PICODATA_ITEMINFO2_NA, 0, (picoos_uchar*)""); + break; + case PR_OPara: + pr_putItem(this, pr, & (*first),& (*last), PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_FLUSH, PICODATA_ITEMINFO2_NA, 0, (picoos_uchar*)""); + if (picokpr_getOutItemVal(network, outitem) == 1) { + pr_putItem(this, pr, & (*first),& (*last), PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_SIL, PICODATA_ITEMINFO2_NA, PICO_PARAGRAPH_PAUSE_DUR, (picoos_uchar*)""); + } + break; + case PR_OBreak: + if ((picokpr_getOutItemArgOfs(network, outitem) != 0)) { + switch (picokpr_getOutItemType(network, picokpr_getOutItemArgOfs(network, outitem))) { + case PR_OVal: + pr_putItem(this, pr, & (*first),& (*last), PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_SIL, PICODATA_ITEMINFO2_NA, picokpr_getOutItemVal(network, picokpr_getOutItemArgOfs(network, outitem)), (picoos_uchar*)""); + break; + case PR_OVar: + lvar = pr_findVariable(vars,picokpr_getOutItemVal(network, picokpr_getOutItemArgOfs(network, outitem))); + if ((lvar != NULL) && (lvar->first != NULL) && (lvar->first->head.type == PICODATA_ITEM_TOKEN)) { + pr_putItem(this, pr, & (*first),& (*last), PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_SIL, PICODATA_ITEMINFO2_NA, picoos_atoi((picoos_char*)lvar->first->data), (picoos_uchar*)""); + } + break; + default: + pr_startItemList(& lf,& ll); + pr_getOutputItemList(this, pr, network,picokpr_getOutItemArgOfs(network, outitem),vars,& lf,& ll); + if (pr->outOfMemory) return; + if (((lf != NULL) && (lf->head.type == PICODATA_ITEM_TOKEN))) { + pr_putItem(this, pr, & (*first),& (*last), PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_SIL, PICODATA_ITEMINFO2_NA, picoos_atoi((picoos_char*)lf->data), (picoos_uchar*)""); + } + break; + } + } + break; + case PR_OVoice: case PR_OContext: case PR_OMark: + if (picokpr_getOutItemType(network, outitem) == PR_OVoice) { + lcmd = PICODATA_ITEMINFO1_CMD_VOICE; + pr->tmpStr1[0] = 0; + lnum = 1; + } else if (picokpr_getOutItemType(network, outitem) == PR_OContext) { + lcmd = PICODATA_ITEMINFO1_CMD_CONTEXT; + pr_strcpy(pr->tmpStr1, (picoos_uchar*)PICO_CONTEXT_DEFAULT); + lnum = 1; + } else if ((picokpr_getOutItemType(network, outitem) == PR_OMark)) { + lcmd = PICODATA_ITEMINFO1_CMD_MARKER; + pr->tmpStr1[0] = 0; + lnum = 0; + } + if (picokpr_getOutItemArgOfs(network, outitem) != 0) { + switch (picokpr_getOutItemType(network, picokpr_getOutItemArgOfs(network, outitem))) { + case PR_OVar: + lvar = pr_findVariable(vars,picokpr_getOutItemVal(network, picokpr_getOutItemArgOfs(network, outitem))); + if (lvar != NULL) { + litem = lvar->first; + } + pr->tmpStr1[0] = 0; + while (litem != NULL) { + if (litem->head.type == PICODATA_ITEM_TOKEN) { + pr_strcat(pr->tmpStr1,litem->data); + } + litem = litem->next; + } + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD, lcmd,lnum,0,pr->tmpStr1); + break; + case PR_OStr: + if (picokpr_getOutItemStrOfs(network, picokpr_getOutItemArgOfs(network, outitem)) != 0) { + lstrp = picokpr_getOutItemStr(network, picokpr_getOutItemArgOfs(network, outitem)); + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD,lcmd,lnum,0,lstrp); + } + break; + default: + pr_startItemList(& lf,& ll); + pr_getOutputItemList(this, pr, network,picokpr_getOutItemArgOfs(network, outitem),vars,& lf,& ll); + if (pr->outOfMemory) return; + if (((lf != NULL) && (lf->head.type == PICODATA_ITEM_TOKEN))) { + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD,lcmd,lnum,0,lf->data); + } + break; + } + } else { + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD,lcmd,lnum,0,pr->tmpStr1); + } + break; + case PR_OGenFile: + if (picokpr_getOutItemArgOfs(network, outitem) != 0) { + lcmd = PICODATA_ITEMINFO1_CMD_SAVE; + } else { + lcmd = PICODATA_ITEMINFO1_CMD_UNSAVE; + } + pr->tmpStr1[0] = 0; + lnum = 0; + if (picokpr_getOutItemArgOfs(network, outitem) != 0) { + switch (picokpr_getOutItemType(network, picokpr_getOutItemArgOfs(network, outitem))) { + case PR_OVar: + lvar = pr_findVariable(vars,picokpr_getOutItemVal(network, picokpr_getOutItemArgOfs(network, outitem))); + if (lvar != NULL) { + litem = lvar->first; + } + pr->tmpStr1[0] = 0; + while (litem != NULL) { + if (litem->head.type == PICODATA_ITEM_TOKEN) { + pr_strcat(pr->tmpStr1,litem->data); + } + litem = litem->next; + } + if ((lnum = picodata_getPuTypeFromExtension(pr->tmpStr1, /*input*/FALSE)) != PICODATA_ITEMINFO2_CMD_TO_UNKNOWN) { + if (pr->saveFile[0] != 0) { + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_UNSAVE, + picodata_getPuTypeFromExtension(pr->saveFile, /*input*/FALSE),0,pr->saveFile); + } + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD, lcmd,lnum,0,pr->tmpStr1); + pr_strcpy(pr->saveFile, pr->tmpStr1); + } + break; + case PR_OStr: + if (picokpr_getOutItemStrOfs(network, picokpr_getOutItemArgOfs(network, outitem)) != 0) { + lstrp = picokpr_getOutItemStr(network, picokpr_getOutItemArgOfs(network, outitem)); + if ((lnum = picodata_getPuTypeFromExtension(lstrp, /*input*/FALSE)) != PICODATA_ITEMINFO2_CMD_TO_UNKNOWN) { + if (pr->saveFile[0] != 0) { + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_UNSAVE, + picodata_getPuTypeFromExtension(pr->saveFile, /*input*/FALSE),0,pr->saveFile); + } + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD, lcmd,lnum,0,lstrp); + pr_strcpy(pr->saveFile, lstrp); + } + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD,lcmd,lnum,0,lstrp); + } + break; + default: + pr_startItemList(& lf,& ll); + pr_getOutputItemList(this, pr, network,picokpr_getOutItemArgOfs(network, outitem),vars,& lf,& ll); + if (pr->outOfMemory) return; + if (((lf != NULL) && (lf->head.type == PICODATA_ITEM_TOKEN))) { + if ((lnum = picodata_getPuTypeFromExtension(lf->data, /*input*/FALSE)) != PICODATA_ITEMINFO2_CMD_TO_UNKNOWN) { + if (pr->saveFile[0] != 0) { + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_UNSAVE, + picodata_getPuTypeFromExtension(pr->saveFile, /*input*/FALSE),0,pr->saveFile); + } + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD, lcmd,lnum,0,lf->data); + pr_strcpy(pr->saveFile, lf->data); + } + } + break; + } +/* + } else { + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD,lcmd,lnum,0,pr->tmpStr1); +*/ + } + break; + case PR_OUseSig: case PR_OPlay: + lout = FALSE; + lf0beg = -(1); + lf0end = -(1); + lxfadebeg[0] = 0; + lxfadeend[0] = 0; + pr->tmpStr1[0] = 0; + if ((picokpr_getOutItemType(network, outitem) == PR_OUseSig)) { + lcmd = PICODATA_ITEMINFO1_CMD_IGNSIG; + } else { + lcmd = PICODATA_ITEMINFO1_CMD_IGNORE; + } + if (picokpr_getOutItemArgOfs(network, outitem) != 0) { + linfo2 = PICODATA_ITEMINFO2_CMD_START; + } else { + linfo2 = PICODATA_ITEMINFO2_CMD_END; + } + if (picokpr_getOutItemArgOfs(network, outitem) != 0) { + switch (picokpr_getOutItemType(network, picokpr_getOutItemArgOfs(network, outitem))) { + case PR_OVar: + lvar = pr_findVariable(vars,picokpr_getOutItemVal(network, picokpr_getOutItemArgOfs(network, outitem))); + if (lvar != NULL) { + litem = lvar->first; + } + pr->tmpStr1[0] = 0; + while (litem != NULL) { + if (litem->head.type == PICODATA_ITEM_TOKEN) { + pr_strcat(pr->tmpStr1,litem->data); + } + litem = litem->next; + } + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_PLAY, + picodata_getPuTypeFromExtension(pr->tmpStr1, /*input*/TRUE),0, pr->tmpStr1); + lout = TRUE; + break; + case PR_OStr: + if (picokpr_getOutItemStrOfs(network, picokpr_getOutItemArgOfs(network, outitem)) != 0) { + lstrp = picokpr_getOutItemStr(network, picokpr_getOutItemArgOfs(network, outitem)); + pr_strcpy(pr->tmpStr1, lstrp); + lout = TRUE; + } + break; + default: + pr_startItemList(& lf,& ll); + pr_getOutputItemList(this, pr, network,picokpr_getOutItemArgOfs(network, outitem),vars,& lf,& ll); + if (pr->outOfMemory) return; + if ((lf != NULL) && (lf->head.type == PICODATA_ITEM_TOKEN)) { + pr_strcpy(pr->tmpStr1, lf->data); + lout = TRUE; + } + break; + } + } + argOfs = picokpr_getOutItemArgOfs(network, outitem); + if (argOfs != 0) { + nextOfs = picokpr_getOutItemNextOfs(network, outitem); + if (nextOfs != 0) { + if (picokpr_getOutItemType(network, nextOfs) == PR_OVal) { + lf0beg = picokpr_getOutItemVal(network, nextOfs); + } + nextOfs2 = picokpr_getOutItemNextOfs(network, nextOfs); + if (nextOfs2 != 0) { + if (picokpr_getOutItemType(network, nextOfs2) == PR_OVal) { + lf0end = picokpr_getOutItemVal(network, nextOfs2); + } + nextOfs3 = picokpr_getOutItemNextOfs(network, nextOfs2); + if (nextOfs3 != 0) { + if ((picokpr_getOutItemType(network, nextOfs3) == PR_OStr) && (picokpr_getOutItemStrOfs(network, nextOfs3) != 0)) { + lstrp = picokpr_getOutItemStr(network, nextOfs3); + pr_strcpy(lxfadebeg, lstrp); + } + nextOfs4 = picokpr_getOutItemNextOfs(network, nextOfs3); + if (nextOfs4 != 0) { + if ((picokpr_getOutItemType(network, nextOfs4) == PR_OStr) && (picokpr_getOutItemStrOfs(network, nextOfs4) != 0)) { + lstrp = picokpr_getOutItemStr(network, nextOfs4); + pr_strcpy(lxfadeend, lstrp); + } + } + } + } + } + } + if (lout) { + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD,PICODATA_ITEMINFO1_CMD_PLAY, + picodata_getPuTypeFromExtension(pr->tmpStr1, /*input*/TRUE),0,pr->tmpStr1); + } + pr_putItem(this, pr,& (*first),& (*last),PICODATA_ITEM_CMD,lcmd,linfo2,0,(picoos_uchar*)""); + break; + default: + PICODBG_INFO(("unknown command")); + break; + } +} + + +static void pr_getOutputItemList (picodata_ProcessingUnit this, + pr_subobj_t * pr, + picokpr_Preproc network, + picokpr_OutItemArrOffset outitem, + pr_OutItemVarPtr vars, + pr_ioItemPtr * first, + pr_ioItemPtr * last) +{ + + picokpr_OutItemArrOffset lo; + picoos_int32 llen; + picoos_int32 llen2; + picokpr_VarStrPtr lstrp; + picoos_int32 lval32; + picoos_int32 li; + picoos_int32 li2; + picoos_int32 ln; + picoos_int32 ln2; + pr_ioItemPtr litem2; + pr_ioItemPtr lf; + pr_ioItemPtr ll; + picoos_int32 lid; + picoos_uint8 ltype; + picoos_int8 lsubtype; + pr_OutItemVarPtr lvar; + picoos_int32 lspellmode; + picoos_int32 largOfs; + picoos_int32 lnextOfs; + + + lo = outitem; + while (lo != 0) { + switch (picokpr_getOutItemType(network, lo)) { + case PR_OStr: + lstrp = picokpr_getOutItemStr(network, lo); + if (pr->outOfMemory) return; + pr_initItem(this, &pr->tmpItem); + pr->tmpItem.head.type = PICODATA_ITEM_TOKEN; + pr->tmpItem.head.info1 = PICODATA_ITEMINFO1_TOKTYPE_UNDEFINED; + pr->tmpItem.head.info2 = -1; + pr->tmpItem.head.len = pr_strcpy(pr->tmpItem.data, lstrp); + pr_copyItem(this, pr_WorkMem, &pr->tmpItem, &litem2); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last),litem2); + break; + case PR_OVar: + lvar = pr_findVariable(vars,picokpr_getOutItemVal(network, lo)); + if (lvar != NULL) { + lf = lvar->first; + } else { + lf = NULL; + } + while (lf != NULL) { + pr_copyItem(this, pr_WorkMem,& (*lf),& litem2); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last),litem2); + lf = lf->next; + } + break; + case PR_OSpell: + lspellmode = PR_SPELL; + largOfs = picokpr_getOutItemArgOfs(network, lo); + if ((largOfs!= 0) && ((lnextOfs = picokpr_getOutItemNextOfs(network, largOfs)) != 0)) { + lspellmode = picokpr_getOutItemVal(network, lnextOfs); + } + pr_startItemList(& lf,& ll); + pr_getOutputItemList(this, pr, network,largOfs,vars,& lf,& ll); + if (pr->outOfMemory) return; + while (lf != NULL) { + switch (lf->head.type) { + case PICODATA_ITEM_TOKEN: + li = 0; + ln = pr_strlen(lf->data); + while (li < ln) { + pr_initItem(this, &pr->tmpItem); + if (pr->outOfMemory) return; + pr->tmpItem.head.type = PICODATA_ITEM_TOKEN; + pr->tmpItem.head.info1 = lf->head.info1; + pr->tmpItem.head.info2 = lf->head.info2; + pr->tmpItem.head.len = picobase_det_utf8_length(lf->data[li]); + for (li2 = 0; li2 < pr->tmpItem.head.len; li2++) { + pr->tmpItem.data[li2] = lf->data[li]; + li++; + } + pr->tmpItem.data[pr->tmpItem.head.len] = 0; + pr->tmpItem.val = 0; + lid = picoktab_graphOffset(pr->graphs,pr->tmpItem.data); + if (lid > 0) { + if (picoktab_getIntPropTokenType(pr->graphs, lid, <ype)) { + if (ltype == PICODATA_ITEMINFO1_TOKTYPE_LETTERV) { + pr->tmpItem.head.len = pr_strcat(pr->tmpItem.data,(picoos_uchar*)SPEC_CHAR); + } + } + picoktab_getIntPropTokenSubType(pr->graphs, lid, &lsubtype); + } else { + ltype = PICODATA_ITEMINFO1_TOKTYPE_UNDEFINED; + lsubtype = -(1); + } + pr_copyItem(this, pr_WorkMem, &pr->tmpItem, &litem2); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last), litem2); + if (lspellmode == PR_SPELL_WITH_PHRASE_BREAK) { + pr_initItem(this, &pr->tmpItem); + pr->tmpItem.head.type = PICODATA_ITEM_TOKEN; + pr->tmpItem.head.info1 = PICODATA_ITEMINFO1_TOKTYPE_CHAR; + pr->tmpItem.head.info2 = lsubtype; + pr->tmpItem.head.len = 1; + pr->tmpItem.data[0] = ','; + pr->tmpItem.data[1] = 0; + pr->tmpItem.val = 0; + pr_copyItem(this, pr_WorkMem, &pr->tmpItem, &litem2); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last),litem2); + } else if (lspellmode == PR_SPELL_WITH_SENTENCE_BREAK) { + pr_initItem(this, &pr->tmpItem); + pr->tmpItem.head.type = PICODATA_ITEM_CMD; + pr->tmpItem.head.info1 = PICODATA_ITEMINFO1_CMD_FLUSH; + pr->tmpItem.head.info2 = PICODATA_ITEMINFO2_NA; + pr->tmpItem.head.len = 0; + pr_copyItem(this, pr_WorkMem, &pr->tmpItem, &litem2); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last),litem2); + } else if (lspellmode > 0) { + pr_initItem(this, &pr->tmpItem); + pr->tmpItem.head.type = PICODATA_ITEM_TOKEN; + pr->tmpItem.head.info1 = PICODATA_ITEMINFO1_TOKTYPE_CHAR; + pr->tmpItem.head.info2 = lsubtype; + pr->tmpItem.head.len = 1; + pr->tmpItem.data[0] = ','; + pr->tmpItem.data[1] = 0; + pr->tmpItem.val = 0; + pr_copyItem(this, pr_WorkMem, &pr->tmpItem, &litem2); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last),litem2); + } + } + break; + default: + pr_copyItem(this, pr_WorkMem,& (*lf),& litem2); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last),litem2); + break; + } + ll = lf; + lf = lf->next; + ll->next = NULL; + } + break; + case PR_OConcat: + pr_startItemList(& lf,& ll); + pr_getOutputItemList(this, pr, network,picokpr_getOutItemArgOfs(network, lo),vars,& lf,& ll); + if (pr->outOfMemory) return; + pr_initItem(this, &pr->tmpItem); + pr->tmpItem.head.type = PICODATA_ITEM_TOKEN; + pr->tmpItem.head.info1 = PICODATA_ITEMINFO1_TOKTYPE_UNDEFINED; + pr->tmpItem.head.info2 = -(1); + pr->tmpItem.head.len = 0; + pr->tmpItem.data[0] = 0; + pr->tmpItem.val = 0; + while (lf != NULL) { + switch (lf->head.type) { + case PICODATA_ITEM_TOKEN: + pr->tmpItem.head.len = pr_strcat(pr->tmpItem.data,lf->data); + break; + case PICODATA_ITEM_CMD: + pr_copyItem(this, pr_WorkMem, &pr->tmpItem, &litem2); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last),litem2); + + pr_copyItem(this, pr_WorkMem, lf, &litem2); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last),litem2); + + pr_initItem(this, &pr->tmpItem); + pr->tmpItem.head.type = PICODATA_ITEM_TOKEN; + pr->tmpItem.head.info1 = PICODATA_ITEMINFO1_TOKTYPE_UNDEFINED; + pr->tmpItem.head.info2 = -(1); + pr->tmpItem.head.len = 0; + pr->tmpItem.data[0] = 0; + pr->tmpItem.val = 0; + break; + default: + break; + } + lf = lf->next; + } + pr_copyItem(this, pr_WorkMem, &pr->tmpItem, &litem2); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last),litem2); + break; + case PR_ORomanToCard: + pr_startItemList(& lf,& ll); + pr_getOutputItemList(this, pr, network,picokpr_getOutItemArgOfs(network, lo),vars,& lf,& ll); + if (pr->outOfMemory) return; + if ((lf != NULL) && (lf->head.type == PICODATA_ITEM_TOKEN)) { + pr_initItem(this, &pr->tmpItem); + pr_copyItemContent(this, lf, &pr->tmpItem); + if (pr_isLatinNumber(lf->data, & lval32)) { + pr_int_to_string(lval32, (picoos_char *)pr->tmpItem.data, PR_MAX_DATA_LEN_Z); + pr->tmpItem.head.len = pr_strlen(pr->tmpItem.data); + pr->tmpItem.val = lval32; + } + pr_copyItem(this, pr_WorkMem, &pr->tmpItem, &litem2); + pr_appendItem(this, & (*first),& (*last),litem2); + } + break; + case PR_OVal: + break; + case PR_OLeft: + pr_startItemList(& lf,& ll); + pr_getOutputItemList(this, pr, network,picokpr_getOutItemNextOfs(network, picokpr_getOutItemArgOfs(network, lo)),vars,& lf,& ll); + if (pr->outOfMemory) return; + if ((lf != NULL) && (lf->head.type == PICODATA_ITEM_TOKEN)) { + pr_initItem(this, &pr->tmpItem); + pr_copyItemContent(this, lf, &pr->tmpItem); + llen = lf->head.len; + llen2 = picobase_utf8_length(pr->tmpItem.data,PR_MAX_DATA_LEN); + ln = 0; + ln2 = 0; + largOfs = picokpr_getOutItemVal(network, picokpr_getOutItemArgOfs(network, lo)); + while ((ln < llen) && (ln2 < llen2) && (ln2 < largOfs)) { + ln = ln + picobase_det_utf8_length(pr->tmpItem.data[ln]); + ln2++; + } + pr->tmpItem.data[ln] = 0; + pr->tmpItem.head.len = ln; + pr_copyItem(this, pr_WorkMem, &pr->tmpItem, &litem2); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last),litem2); + } + break; + case PR_ORight: + pr_startItemList(& lf,& ll); + pr_getOutputItemList(this, pr, network,picokpr_getOutItemNextOfs(network, picokpr_getOutItemArgOfs(network, lo)),vars,& lf,& ll); + if (pr->outOfMemory) return; + if ((lf != NULL) && (lf->head.type == PICODATA_ITEM_TOKEN)) { + pr_initItem(this, &pr->tmpItem); + pr_copyItemContent(this, lf, & pr->tmpItem); + llen = lf->head.len; + llen2 = picobase_utf8_length(pr->tmpItem.data,PR_MAX_DATA_LEN); + ln = 0; + ln2 = 0; + while ((ln < llen) && (ln2 < llen2) && (ln2 < (llen2 - picokpr_getOutItemVal(network, picokpr_getOutItemArgOfs(network, lo))))) { + ln = ln + picobase_det_utf8_length(pr->tmpItem.data[ln]); + ln2++; + } + pr->tmpItem.head.len = pr_removeSubstring(0,ln,pr->tmpItem.data); + pr_copyItem(this, pr_WorkMem, &pr->tmpItem, & litem2); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last),litem2); + } + break; + case PR_OItem: + pr_startItemList(& lf,& ll); + pr_getOutputItemList(this, pr, network,picokpr_getOutItemNextOfs(network, picokpr_getOutItemArgOfs(network, lo)),vars,& lf,& ll); + if (pr->outOfMemory) return; + ln = picokpr_getOutItemVal(network, picokpr_getOutItemArgOfs(network, lo)); + li = 1; + while ((li < ln) && (lf != NULL)) { + lf = lf->next; + li++; + } + if ((lf != NULL) && (li == ln) && (lf->head.type == PICODATA_ITEM_TOKEN)) { + pr_copyItem(this, pr_WorkMem, lf, & litem2); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last),litem2); + } + break; + case PR_ORLZ: + pr_startItemList(& lf,& ll); + pr_getOutputItemList(this, pr, network, picokpr_getOutItemArgOfs(network, lo),vars,& lf,& ll); + if (pr->outOfMemory) return; + if ((lf != NULL) && (lf->head.type == PICODATA_ITEM_TOKEN)) { + pr_initItem(this, &pr->tmpItem); + pr_copyItemContent(this, lf, & pr->tmpItem); + li = 0; + while ((li < lf->head.len) && (pr->tmpItem.data[li] == '0')) { + li++; + } + pr->tmpItem.head.len = pr_removeSubstring(0,li,pr->tmpItem.data); + pr_copyItem(this, pr_WorkMem, &pr->tmpItem, & litem2); + if (pr->outOfMemory) return; + pr_appendItem(this, & (*first),& (*last),litem2); + } + break; + case PR_OIgnore: case PR_OPitch: case PR_OSpeed: case PR_OVolume: case PR_OPhonSVOXPA: case PR_OPhonSAMPA: case PR_OBreak: case PR_OMark: case PR_OPara: case PR_OSent: case PR_OPlay: + case PR_OUseSig: case PR_OGenFile: case PR_OAudioEdit: case PR_OContext: case PR_OVoice: + pr_genCommands(this, pr, network,lo,vars,& (*first),& (*last)); + if (pr->outOfMemory) return; + break; + default: + PICODBG_INFO(("unkown command")); + break; + } + lo = picokpr_getOutItemNextOfs(network, lo); + } +} + + +static picoos_int32 pr_attrVal (picokpr_Preproc network, picokpr_TokArrOffset tok, pr_TokSetEleWP type) +{ + + pr_TokSetEleWP tse; + picoos_int32 n; + picokpr_TokSetWP set; + + n = 0; + tse = PR_FIRST_TSE_WP; + set = picokpr_getTokSetWP(network, tok); + while (tse < type) { + if (((1<rbestpath.rlen) { + with__0 = & pr->rbestpath.rele[*i]; + li = 0; + if (*i > 0) { + while ((li < 127) && (li < pr->rbestpath.rele[*i].rdepth)) { + pr->lspaces[li++] = ' '; + } + } + pr->lspaces[li] = 0; + if (with__0->rprodname != 0) { + PICODBG_INFO(("pp path :%s%s(", pr->lspaces, picokpr_getVarStrPtr(with__0->rnetwork,with__0->rprodname))); + } + if ((pr->ritems[with__0->ritemid+1] != NULL) && (pr->ritems[with__0->ritemid+1]->head.type == PICODATA_ITEM_TOKEN)) { + PICODBG_INFO(("pp in (1): %s'%s'", pr->lspaces, pr->ritems[with__0->ritemid+1]->data)); + } + if ((pr->ritems[with__0->ritemid+1] != NULL)) { + while ((pr->rinItemList != NULL) && (pr->rinItemList != pr->ritems[with__0->ritemid+1]) && (pr->rinItemList->head.type != PICODATA_ITEM_TOKEN)) { + lit = pr->rinItemList; + pr->rinItemList = pr->rinItemList->next; + lit->next = NULL; + pr_copyItem(this, pr_WorkMem,& (*lit),& lcopy); + if (pr->outOfMemory) return; + pr_disposeItem(this, & lit); + pr_appendItem(this, & (*o),& (*ol),lcopy); + } + if (pr->rinItemList != NULL) { + lit = pr->rinItemList; + pr->rinItemList = pr->rinItemList->next; + lit->next = NULL; + } else { + lit = NULL; + } + } + wpset = picokpr_getTokSetWP(with__0->rnetwork, with__0->rtok); + npset = picokpr_getTokSetNP(with__0->rnetwork, with__0->rtok); + + if ((PR_TSE_MASK_PROD & wpset) != 0) { + if ((PR_TSE_MASK_VAR & wpset) != 0) { + lvar = pr_findVariable(lvars,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEVar)); + if (lvar == NULL) { + pr_ALLOCATE(this, pr_WorkMem, (void *) & lvar,(sizeof (*lvar))); + lvar->next = lvars; + lvar->id = pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEVar); + lvars = lvar; + } + pr_startItemList(& lvar->first,& lvar->last); + pr_getOutput(this, pr, & (*i),(d + 1),& lvar->first,& lvar->last); + if (pr->outOfMemory) return; + } else { + pr_startItemList(& ldit,& ldlit); + pr_getOutput(this, pr, & (*i),(d + 1),& ldit,& ldlit); + if (pr->outOfMemory) return; + } + (*i)++; + } else if ((PR_TSE_MASK_VAR & wpset) != 0) { + lvar = pr_findVariable(lvars,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEVar)); + if (lvar == NULL) { + pr_ALLOCATE(this, pr_WorkMem, (void *) & lvar,(sizeof (*lvar))); + lvar->next = lvars; + lvar->id = pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEVar); + lvars = lvar; + } + if (((PR_TSE_MASK_LEX & wpset) != 0) && ((PR_TSE_MASK_LETTER & npset) == 0)) { + if (lfirst) { + pr_newItem(this, pr_WorkMem,& lit, PICODATA_ITEM_TOKEN, sizeof(struct pr_ioItem), /*inItem*/FALSE); + if (pr->outOfMemory) return; + lit->head.type = PICODATA_ITEM_TOKEN; + lit->head.info1 = pr->ritems[with__0->ritemid+1]->head.info1; + lit->head.info2 = pr->ritems[with__0->ritemid+1]->head.info2; + if (pr->ritems[with__0->ritemid+1]->head.info1 == PICODATA_ITEMINFO1_TOKTYPE_SPACE) { + lit->head.len = pr_strcpy(lit->data, (picoos_uchar*)"_"); + } else { + lit->head.len = pr_strcpy(lit->data, pr->ritems[with__0->ritemid+1]->data); + } + lvar->first = lit; + lvar->last = lit; + lfirst = FALSE; + } else { + if (pr->ritems[with__0->ritemid+1]->head.info1 == PICODATA_ITEMINFO1_TOKTYPE_SPACE) { + lvar->last->head.len = pr_strcat(lvar->last->data,(picoos_uchar*)"_"); + } else { + lvar->last->head.len = pr_strcat(lvar->last->data,pr->ritems[with__0->ritemid+1]->data); + } + lvar->last->head.info1 = PICODATA_ITEMINFO1_TOKTYPE_UNDEFINED; + lvar->last->head.info2 = -(1); + } + } else { + lvar->first = pr->ritems[with__0->ritemid+1]; + lvar->last = pr->ritems[with__0->ritemid+1]; + } + (*i)++; + } else if ((PR_TSE_MASK_OUT & wpset) != 0) { + pr_getOutputItemList(this, pr, with__0->rnetwork,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEOut),lvars,& (*o),& (*ol)); + if (pr->outOfMemory) return; + (*i)++; + } else if (((*i) < (pr->rbestpath.rlen - 1)) && (d != pr->rbestpath.rele[(*i) + 1].rdepth)) { + if ((*i > 0) && (with__0->rdepth-1) == pr->rbestpath.rele[*i + 1].rdepth) { + li = 0; + while ((li < 127) && (li < with__0->rdepth-1)) { + pr->lspaces[li++] = ' '; + } + pr->lspaces[li] = 0; + PICODBG_INFO(("pp path :%s)", pr->lspaces)); + } + return; + } else { + (*i)++; + } + if ((PR_TSE_MASK_LEX & wpset) == 0) { + lfirst = TRUE; + } + } + li = 0; + while ((li < 127) && (li < pr->rbestpath.rele[*i].rdepth-1)) { + pr->lspaces[li++] = ' '; + } + pr->lspaces[li] = 0; + PICODBG_INFO(("pp path :%s)", pr->lspaces)); +} + + +static void pr_outputPath (picodata_ProcessingUnit this, pr_subobj_t * pr) +{ + register struct pr_PathEle * with__0; + picoos_int32 li; + pr_ioItemPtr lf; + pr_ioItemPtr ll; + pr_ioItemPtr lit; + pr_ioItemPtr lit2; + pr_MemState lmemState; + picoos_bool lastPlayFileFound; + + pr_getMemState(this, pr_WorkMem, & lmemState); + lf = NULL; + ll = NULL; + li = -(1); + pr_getOutput(this, pr, & li,1,& lf,& ll); + if (pr->outOfMemory) return; + lastPlayFileFound = TRUE; + while (lf != NULL) { + lit = lf; + lf = lf->next; + lit->next = NULL; + if (pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_PLAY)) { + lastPlayFileFound = picoos_FileExists(this->common, (picoos_char*)lit->data); + if (!lastPlayFileFound) { + PICODBG_WARN(("file '%s' not found; synthesizing enclosed text instead", lit->data)); + picoos_emRaiseWarning(this->common->em, PICO_EXC_CANT_OPEN_FILE, (picoos_char*)"", (picoos_char*)"file '%s' not found; synthesizing enclosed text instead",lit->data); + } + } + if (pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_PHONEME) && pr_isCmdInfo2(lit, PICODATA_ITEMINFO2_CMD_START)) { + pr->insidePhoneme = TRUE; + } else if (pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_PHONEME)&& pr_isCmdInfo2(lit, PICODATA_ITEMINFO2_CMD_END)) { + pr->insidePhoneme = FALSE; + } + if ((pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_PLAY) && !lastPlayFileFound)) { + } else if (pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_IGNORE) && pr_isCmdInfo2(lit, PICODATA_ITEMINFO2_CMD_START)) { + if (lastPlayFileFound) { + pr->rignore++; + } + } else if (pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_IGNORE) && pr_isCmdInfo2(lit, PICODATA_ITEMINFO2_CMD_END)) { + if (lastPlayFileFound) { + if (pr->rignore > 0) { + pr->rignore--; + } + } + } else if (pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_IGNSIG) && pr_isCmdInfo2(lit, PICODATA_ITEMINFO2_CMD_START) && !lastPlayFileFound) { + } else if (pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_IGNSIG) && pr_isCmdInfo2(lit, PICODATA_ITEMINFO2_CMD_END) && !lastPlayFileFound) { + } else if (pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_CONTEXT)) { + if (pr->rignore <= 0) { + pr_setContext(this, pr, lit->data); + } + } else if (pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_VOICE)) { + if (pr->rignore <= 0) { + pr_copyItem(this, pr_DynMem,lit,& lit2); + if (pr->outOfMemory) return; + pr_appendItem(this, & pr->routItemList,& pr->rlastOutItem, lit2); + } + } else { + if ((pr->rignore <= 0) && !(pr->insidePhoneme && (pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_PLAY) || + pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_IGNSIG)))) { + PICODBG_INFO(("pp out(1): '%s'", lit->data)); + pr_copyItem(this, pr_DynMem,lit,& lit2); + if (pr->outOfMemory) return; + pr_appendItemToOutItemList(this, pr, & pr->routItemList,& pr->rlastOutItem,lit2); + if (pr->outOfMemory) return; + } + } + } + for (li = 0; lirbestpath.rlen; li++) { + with__0 = & pr->rbestpath.rele[li]; + pr_disposeItem(this, & pr->ritems[with__0->ritemid+1]); + } + pr_resetMemState(this, pr_WorkMem, lmemState); +} + +/* *****************************************************************************/ + +static void pr_compare (picoos_uchar str1lc[], picoos_uchar str2[], picoos_int16 * result) +{ + + picoos_int32 i; + picoos_int32 j; + picoos_int32 l; + picoos_uint32 pos; + picoos_bool finished1; + picoos_bool finished2; + picoos_bool done; + picobase_utf8char utf8char; + + pos = 0; + l = picobase_get_next_utf8char(str2, PR_MAX_DATA_LEN, & pos,utf8char); + picobase_lowercase_utf8_str(utf8char,(picoos_char*)utf8char,PICOBASE_UTF8_MAXLEN+1, &done); + l = picobase_det_utf8_length(utf8char[0]); + j = 0; + i = 0; + while ((i < PR_MAX_DATA_LEN) && (str1lc[i] != 0) && (l > 0) && (j <= 3) && (str1lc[i] == utf8char[j])) { + i++; + j++; + if (j >= l) { + l = picobase_get_next_utf8char(str2, PR_MAX_DATA_LEN, & pos,utf8char); + picobase_lowercase_utf8_str(utf8char,(picoos_char*)utf8char,PICOBASE_UTF8_MAXLEN+1, &done); + l = picobase_det_utf8_length(utf8char[0]); + j = 0; + } + } + finished1 = (i >= PR_MAX_DATA_LEN) || (str1lc[i] == 0); + finished2 = (j > 3) || (utf8char[j] == 0); + if (finished1 && finished2) { + *result = PR_EQUAL; + } else if (finished1) { + *result = PR_SMALLER; + } else if (finished2) { + *result = PR_LARGER; + } else { + if (str1lc[i] < utf8char[j]) { + *result = PR_SMALLER; + } else { + *result = PR_LARGER; + } + } +} + + +static picoos_bool pr_hasToken (picokpr_TokSetWP * tswp, picokpr_TokSetNP * tsnp) +{ + return (((( PR_TSE_MASK_SPACE | PR_TSE_MASK_DIGIT | PR_TSE_MASK_LETTER | PR_TSE_MASK_SEQ + | PR_TSE_MASK_CHAR | PR_TSE_MASK_BEGIN | PR_TSE_MASK_END) & (*tsnp)) != 0) || + ((PR_TSE_MASK_LEX & (*tswp)) != 0)); +} + + +static picoos_bool pr_getNextToken (picodata_ProcessingUnit this, pr_subobj_t * pr) +{ + register struct pr_PathEle * with__0; + picoos_int32 len; + picokpr_TokSetNP npset; + + len = pr->ractpath.rlen; + with__0 = & pr->ractpath.rele[len - 1]; + npset = picokpr_getTokSetNP(with__0->rnetwork, with__0->rtok); + if ((len > 0) && (pr->ractpath.rlen < PR_MAX_PATH_LEN) && ((PR_TSE_MASK_NEXT & npset) != 0)) { + pr_initPathEle(& pr->ractpath.rele[len]); + pr->ractpath.rele[len].rnetwork = with__0->rnetwork; + pr->ractpath.rele[len].rtok = picokpr_getTokNextOfs(with__0->rnetwork, with__0->rtok); + pr->ractpath.rele[len].rdepth = with__0->rdepth; + pr->ractpath.rlen++; + return TRUE; + } else { + if (len >= PR_MAX_PATH_LEN) { + PICODBG_INFO(("max path len reached (pr_getNextToken)")); + } + return FALSE; + } +} + + +static picoos_bool pr_getAltToken (picodata_ProcessingUnit this, pr_subobj_t * pr) +{ + register struct pr_PathEle * with__0; + picokpr_TokArrOffset lTok; + picokpr_TokSetNP npset; + + + with__0 = & pr->ractpath.rele[pr->ractpath.rlen - 1]; + if ((pr->ractpath.rlen > 0) && (pr->ractpath.rlen < PR_MAX_PATH_LEN)) { + npset = picokpr_getTokSetNP(with__0->rnetwork, with__0->rtok); + if (with__0->rcompare == PR_SMALLER) { + if ((PR_TSE_MASK_ALTL & npset) != 0) { + lTok = picokpr_getTokAltLOfs(with__0->rnetwork, with__0->rtok); + } else { + return FALSE; + } + } else { + if ((PR_TSE_MASK_ALTR & npset) != 0) { + lTok = picokpr_getTokAltROfs(with__0->rnetwork, with__0->rtok); + } else { + return FALSE; + } + } + with__0->rlState = PR_LSInit; + with__0->rtok = lTok; + with__0->ritemid = -1; + with__0->rcompare = -1; + with__0->rprodname = 0; + with__0->rprodprefcost = 0; + return TRUE; + } else { + if (pr->ractpath.rlen >= PR_MAX_PATH_LEN) { + PICODBG_INFO(("max path len reached (pr_getAltToken)")); + } + return FALSE; + } +} + + +static picoos_bool pr_findProduction (picodata_ProcessingUnit this, pr_subobj_t * pr, + picoos_uchar str[], picokpr_Preproc * network, picokpr_TokArrOffset * tokOfs) +{ + picoos_bool found; + picoos_int32 p; + picoos_int32 ind; + picoos_int32 i; + picoos_bool done; + picokpr_VarStrPtr lstrp; + picoos_int32 lprodarrlen; + + ind = 0; + pr_getTermPartStr(str,& ind,'.',pr->tmpStr1,& done); + pr_getTermPartStr(str,& ind,'.',pr->tmpStr2,& done); + found = FALSE; + + for (p=0; ppreproc[p] != NULL)) { + if (pr_strEqual(pr->tmpStr1, picokpr_getPreprocNetName(pr->preproc[p]))) { + i = 0; + lprodarrlen = picokpr_getProdArrLen(pr->preproc[p]); + while (!found && (i <= (lprodarrlen - 1))) { + lstrp = picokpr_getVarStrPtr(pr->preproc[p],picokpr_getProdNameOfs(pr->preproc[p], i)); + if (pr_strEqual(pr->tmpStr2, lstrp)) { + *network = pr->preproc[p]; + *tokOfs = picokpr_getProdATokOfs(pr->preproc[p], i); + return TRUE; + } + i++; + } + } + } + } + return FALSE; +} + + +static picoos_bool pr_getProdToken (picodata_ProcessingUnit this, pr_subobj_t * pr) +{ + register struct pr_PathEle * with__0; + picokpr_VarStrPtr lstrp; + picokpr_TokSetWP wpset; + + if ((pr->ractpath.rlen > 0) && (pr->ractpath.rlen < PR_MAX_PATH_LEN)) { + with__0 = & pr->ractpath.rele[pr->ractpath.rlen - 1]; + wpset = picokpr_getTokSetWP(with__0->rnetwork, with__0->rtok); + if ((PR_TSE_MASK_PROD & wpset) != 0) { + if ((PR_TSE_MASK_PRODEXT & wpset) != 0) { + pr_initPathEle(& pr->ractpath.rele[pr->ractpath.rlen]); + lstrp = picokpr_getVarStrPtr(with__0->rnetwork, pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEProdExt)); + if (pr_findProduction(this, pr, lstrp,& pr->ractpath.rele[pr->ractpath.rlen].rnetwork,& pr->ractpath.rele[pr->ractpath.rlen].rtok)) { + with__0->rprodname = picokpr_getProdNameOfs(with__0->rnetwork, pr_attrVal(with__0->rnetwork, with__0->rtok,PR_TSEProd)); + with__0->rprodprefcost = picokpr_getProdPrefCost(with__0->rnetwork, pr_attrVal(with__0->rnetwork,with__0->rtok,PR_TSEProd)); + pr->ractpath.rele[pr->ractpath.rlen].rdepth = with__0->rdepth + 1; + pr->ractpath.rlen++; + return TRUE; + } else { + return FALSE; + } + } else { + pr_initPathEle(& pr->ractpath.rele[pr->ractpath.rlen]); + pr->ractpath.rele[pr->ractpath.rlen].rnetwork = with__0->rnetwork; + pr->ractpath.rele[pr->ractpath.rlen].rtok = picokpr_getProdATokOfs(with__0->rnetwork, pr_attrVal(with__0->rnetwork, with__0->rtok,PR_TSEProd)); + with__0->rprodname = picokpr_getProdNameOfs(with__0->rnetwork, pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEProd)); + with__0->rprodprefcost = picokpr_getProdPrefCost(with__0->rnetwork, pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEProd)); + pr->ractpath.rele[pr->ractpath.rlen].rdepth = with__0->rdepth + 1; + pr->ractpath.rlen++; + return TRUE; + } + } + } + if (pr->ractpath.rlen >= PR_MAX_PATH_LEN) { + PICODBG_INFO(("max path len reached (pr_getProdToken)")); + } + return FALSE; +} + + +static picoos_bool pr_getProdContToken (picodata_ProcessingUnit this, pr_subobj_t * pr) +{ + picoos_int32 li; + + li = pr->ractpath.rlen - 1; + while ((li > 0) && !((pr->ractpath.rele[li].rdepth == (pr->ractpath.rele[pr->ractpath.rlen - 1].rdepth - 1)) && ((PR_TSE_MASK_PROD &picokpr_getTokSetWP(pr->ractpath.rele[li].rnetwork, pr->ractpath.rele[li].rtok)) != 0))) { + li--; + } + if (((li >= 0) && (pr->ractpath.rlen < PR_MAX_PATH_LEN) && (PR_TSE_MASK_NEXT &picokpr_getTokSetNP(pr->ractpath.rele[li].rnetwork, pr->ractpath.rele[li].rtok)) != 0)) { + pr_initPathEle(& pr->ractpath.rele[pr->ractpath.rlen]); + pr->ractpath.rele[pr->ractpath.rlen].rnetwork = pr->ractpath.rele[li].rnetwork; + pr->ractpath.rele[pr->ractpath.rlen].rtok = picokpr_getTokNextOfs(pr->ractpath.rele[li].rnetwork, pr->ractpath.rele[li].rtok); + pr->ractpath.rele[pr->ractpath.rlen].rdepth = pr->ractpath.rele[li].rdepth; + pr->ractpath.rlen++; + return TRUE; + } else { + if (pr->ractpath.rlen >= PR_MAX_PATH_LEN) { + PICODBG_INFO(("max path len reached (pr_getProdContToken)")); + } + return FALSE; + } +} + +/* *****************************************************************************/ + +static picoos_bool pr_getTopLevelToken (picodata_ProcessingUnit this, pr_subobj_t * pr, picoos_bool firstprod) +{ + if (firstprod) { + if (pr->actCtx != NULL) { + pr->prodList = pr->actCtx->rProdList; + } else { + pr->prodList = NULL; + } + } else if (pr->prodList != NULL) { + pr->prodList = pr->prodList->rNext; + } + if ((pr->prodList != NULL) && (pr->prodList->rProdOfs != 0) && (picokpr_getProdATokOfs(pr->prodList->rNetwork, pr->prodList->rProdOfs) != 0)) { + pr_initPathEle(& pr->ractpath.rele[pr->ractpath.rlen]); + pr->ractpath.rele[pr->ractpath.rlen].rdepth = 1; + pr->ractpath.rele[pr->ractpath.rlen].rnetwork = pr->prodList->rNetwork; + pr->ractpath.rele[pr->ractpath.rlen].rtok = picokpr_getProdATokOfs(pr->prodList->rNetwork, pr->prodList->rProdOfs); + pr->ractpath.rele[pr->ractpath.rlen].rlState = PR_LSInit; + pr->ractpath.rele[pr->ractpath.rlen].rcompare = -1; + pr->ractpath.rele[pr->ractpath.rlen].rprodname = picokpr_getProdNameOfs(pr->prodList->rNetwork, pr->prodList->rProdOfs); + pr->ractpath.rele[pr->ractpath.rlen].rprodprefcost = picokpr_getProdPrefCost(pr->prodList->rNetwork, pr->prodList->rProdOfs); + pr->ractpath.rlen++; + return TRUE; + } else { + return FALSE; + } +} + + +static picoos_bool pr_getToken (picodata_ProcessingUnit this, pr_subobj_t * pr) +{ + picoos_int32 ln; + picoos_int32 lid; + + ln = (pr->ractpath.rlen - 2); + while ((ln >= 0) && (pr->ractpath.rele[ln].ritemid == -1)) { + ln = ln - 1; + } + if (ln >= 0) { + lid = pr->ractpath.rele[ln].ritemid + 1; + } else { + lid = 0; + } + if (lid < pr->rnritems) { + pr->ractpath.rele[pr->ractpath.rlen - 1].ritemid = lid; + } else { + pr->ractpath.rele[pr->ractpath.rlen - 1].ritemid = -1; + } + return (lid < pr->rnritems); +} + + +static picoos_bool pr_getNextMultiToken (picodata_ProcessingUnit this, pr_subobj_t * pr) +{ + picoos_int32 len; + + len = pr->ractpath.rlen; + if ((len > 0) && (len < PR_MAX_PATH_LEN)) { + pr->ractpath.rele[len].rtok = pr->ractpath.rele[len - 1].rtok; + pr->ractpath.rele[len].ritemid = -(1); + pr->ractpath.rele[len].rcompare = pr->ractpath.rele[len - 1].rcompare; + pr->ractpath.rele[len].rdepth = pr->ractpath.rele[len - 1].rdepth; + pr->ractpath.rele[len].rlState = PR_LSInit; + pr->ractpath.rlen++; + return TRUE; + } else { + if (len >= PR_MAX_PATH_LEN) { + PICODBG_INFO(("max path len reached (pr_getNextMultiToken)")); + } + return FALSE; + } + return FALSE; +} + + +static pr_MatchState pr_matchMultiToken (picodata_ProcessingUnit this, pr_subobj_t * pr, + picokpr_TokSetNP npset, picokpr_TokSetWP wpset) +{ + picoos_bool lcontinue=FALSE; + picoos_bool lmatch=FALSE; + + if (lmatch) { + return PR_MSMatchedMulti; + } else if (lcontinue) { + return PR_MSMatchedContinue; + } else { + return PR_MSNotMatched; + } + pr = pr; /* avoid warning "var not used in this function"*/ + npset = npset; /* avoid warning "var not used in this function"*/ + wpset = wpset; /* avoid warning "var not used in this function"*/ + +} + + +static pr_MatchState pr_matchTokensSpace (picodata_ProcessingUnit this, pr_subobj_t * pr, picoos_int32 cmpres, + picokpr_TokSetNP npset, picokpr_TokSetWP wpset) +{ + register struct pr_PathEle * with__0; + picoos_int32 llen; + picoos_int32 lulen; + picoos_int32 li; + picokpr_VarStrPtr lstrp; + picoos_int32 leol; + + with__0 = & pr->ractpath.rele[pr->ractpath.rlen - 1]; + if ((PR_TSE_MASK_SPACE & npset) == 0) { + return PR_MSNotMatched; + } + lstrp = (picokpr_VarStrPtr)&pr->ritems[with__0->ritemid+1]->data; + lulen = picobase_utf8_length(lstrp,PR_MAX_DATA_LEN); + if (((PR_TSE_MASK_LEN & wpset) != 0) && (lulen != pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSELen))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_MIN & wpset) != 0) && (lulen < pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEMin))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_MAX & wpset) != 0) && (lulen > pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEMax))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_STR & wpset) != 0) && (cmpres != PR_EQUAL)) { + return PR_MSNotMatched; + } + if ((PR_TSE_MASK_VAL & wpset) != 0) { + leol = 0; + llen = pr_strlen(lstrp); + for (li = 0; li < llen; li++) { + if (lstrp[li] == PR_EOL) { + leol++; + } + } + if (leol != pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEVal)) { + return PR_MSNotMatched; + } + } + if (((PR_TSE_MASK_ID & wpset) != 0) && (pr->ritems[with__0->ritemid+1]->head.info2 != pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEID))) { + return PR_MSNotMatched; + } + return PR_MSMatched; +} + + +static pr_MatchState pr_matchTokensDigit (picodata_ProcessingUnit this, pr_subobj_t * pr, picoos_int32 cmpres, + picokpr_TokSetNP npset, picokpr_TokSetWP wpset) +{ + register struct pr_PathEle * with__0; + picoos_int32 lulen; + picoos_int32 lval; + picokpr_VarStrPtr lstrp; + + with__0 = & pr->ractpath.rele[pr->ractpath.rlen - 1]; + if ((PR_TSE_MASK_DIGIT & npset) == 0) { + return PR_MSNotMatched; + } + lstrp = (picokpr_VarStrPtr)&pr->ritems[with__0->ritemid+1]->data; + lulen = picobase_utf8_length(lstrp,PR_MAX_DATA_LEN); + if ((((PR_TSE_MASK_LEN & wpset) != 0) && (lulen != pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSELen)))) { + return PR_MSNotMatched; + } + lval = pr->ritems[with__0->ritemid+1]->val; + if (((PR_TSE_MASK_MIN & wpset) != 0) && (lval < pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEMin))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_MAX & wpset) != 0) && (lval > pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEMax))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_STR & wpset) != 0) && (cmpres != PR_EQUAL)) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_VAL & wpset) != 0) && (lval != pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEVal))) { + return PR_MSNotMatched; + } + if ((((PR_TSE_MASK_NLZ & npset) != 0) && lstrp[0] == '0')) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_HEAD & wpset) != 0) && !(picokpr_isEqualHead(with__0->rnetwork,lstrp,PR_MAX_DATA_LEN,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEHead)))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_MID & wpset) != 0) && !(picokpr_isEqualMid(with__0->rnetwork,lstrp,PR_MAX_DATA_LEN,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEMid)))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_TAIL & wpset) != 0) && !(picokpr_isEqualTail(with__0->rnetwork,lstrp,PR_MAX_DATA_LEN,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSETail)))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_ID & wpset) != 0) && (pr->ritems[with__0->ritemid+1]->head.info2 != pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEID))) { + return PR_MSNotMatched; + } + return PR_MSMatched; +} + + +static pr_MatchState pr_matchTokensSeq (picodata_ProcessingUnit this, pr_subobj_t * pr, picoos_int32 cmpres, + picokpr_TokSetNP npset, picokpr_TokSetWP wpset) +{ + + register struct pr_PathEle * with__0; + picoos_int32 lulen; + picokpr_VarStrPtr lstrp; + + with__0 = & pr->ractpath.rele[pr->ractpath.rlen - 1]; + + if (!((PR_TSE_MASK_SEQ & npset) != 0)) { + return PR_MSNotMatched; + } + lstrp = (picokpr_VarStrPtr)(void *) &pr->ritems[with__0->ritemid+1]->data; + lulen = picobase_utf8_length(lstrp,PR_MAX_DATA_LEN); + if (((PR_TSE_MASK_LEN & wpset) != 0) && (lulen != pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSELen))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_MIN & wpset) != 0) && (lulen < pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEMin))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_MAX & wpset) != 0) && (lulen > pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEMax))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_STR & wpset) != 0) && (cmpres != PR_EQUAL)) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_HEAD & wpset) != 0) && !(picokpr_isEqualHead(with__0->rnetwork,lstrp,PR_MAX_DATA_LEN,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEHead)))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_MID & wpset) != 0) && !(picokpr_isEqualMid(with__0->rnetwork,lstrp,PR_MAX_DATA_LEN ,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEMid)))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_TAIL & wpset) != 0) && !(picokpr_isEqualTail(with__0->rnetwork,lstrp,PR_MAX_DATA_LEN,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSETail)))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_ID & wpset) != 0) && (pr->ritems[with__0->ritemid+1]->head.info2 != pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEID))) { + return PR_MSNotMatched; + } + return PR_MSMatched; +} + + +static pr_MatchState pr_matchTokensChar (picodata_ProcessingUnit this, pr_subobj_t * pr, picoos_int32 cmpres, + picokpr_TokSetNP npset, picokpr_TokSetWP wpset) +{ + register struct pr_PathEle * with__0; + + with__0 = & pr->ractpath.rele[pr->ractpath.rlen - 1]; + + if (!((PR_TSE_MASK_CHAR & npset) != 0)) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_STR & wpset) != 0) && (cmpres != PR_EQUAL)) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_ID & wpset) != 0) && (pr->ritems[with__0->ritemid+1]->head.info2 != pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEID))) { + return PR_MSNotMatched; + } + return PR_MSMatched; +} + + +static pr_MatchState pr_matchTokensLetter (picodata_ProcessingUnit this, pr_subobj_t * pr, picoos_int32 cmpres, + picokpr_TokSetNP npset, picokpr_TokSetWP wpset) +{ + + register struct pr_PathEle * with__0; + picoos_int32 lulen; + picoos_int32 lromanval; + + with__0 = & pr->ractpath.rele[pr->ractpath.rlen - 1]; + + if ( !((PR_TSE_MASK_LETTER & npset) != 0)) { + return PR_MSNotMatched; + } + lulen = picobase_utf8_length(pr->ritems[with__0->ritemid+1]->data, PR_MAX_DATA_LEN); + if (((PR_TSE_MASK_LEN & wpset) != 0) && (lulen != pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSELen))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_MIN & wpset) != 0) && (lulen < pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEMin))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_MAX & wpset) != 0) && (lulen > pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEMax))) { + return PR_MSNotMatched; + } + if ((PR_TSE_MASK_CI & npset) != 0) { + if (((PR_TSE_MASK_STR & wpset) != 0) && (cmpres != PR_EQUAL)) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_HEAD & wpset) != 0) && !(picokpr_isEqualHead(with__0->rnetwork,pr->ritems[with__0->ritemid+1]->strci,PR_MAX_DATA_LEN,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEHead)))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_MID & wpset) != 0) && !(picokpr_isEqualMid(with__0->rnetwork,pr->ritems[with__0->ritemid+1]->strci,PR_MAX_DATA_LEN,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEMid)))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_TAIL & wpset) != 0) && !(picokpr_isEqualTail(with__0->rnetwork,pr->ritems[with__0->ritemid+1]->strci,PR_MAX_DATA_LEN,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSETail)))) { + return PR_MSNotMatched; + } + } else if ((PR_TSE_MASK_CIS & npset) != 0) { + if (((PR_TSE_MASK_STR & wpset) != 0) && !(picokpr_isEqual(with__0->rnetwork,pr->ritems[with__0->ritemid+1]->strcis,PR_MAX_DATA_LEN,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEStr)))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_HEAD & wpset) != 0) && !(picokpr_isEqualHead(with__0->rnetwork,pr->ritems[with__0->ritemid+1]->strcis,PR_MAX_DATA_LEN,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEHead)))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_MID & wpset) != 0) && !(picokpr_isEqualMid(with__0->rnetwork,pr->ritems[with__0->ritemid+1]->strcis,PR_MAX_DATA_LEN,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEMid)))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_TAIL & wpset) != 0) && !(picokpr_isEqualTail(with__0->rnetwork,pr->ritems[with__0->ritemid+1]->strcis,PR_MAX_DATA_LEN,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSETail)))) { + return PR_MSNotMatched; + } + } else { + if (((PR_TSE_MASK_STR & wpset) != 0) && !(picokpr_isEqual(with__0->rnetwork,pr->ritems[with__0->ritemid+1]->data,PR_MAX_DATA_LEN,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEStr)))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_HEAD & wpset) != 0) && !(picokpr_isEqualHead(with__0->rnetwork,pr->ritems[with__0->ritemid+1]->data,PR_MAX_DATA_LEN,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEHead)))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_MID & wpset) != 0) && !(picokpr_isEqualMid(with__0->rnetwork,pr->ritems[with__0->ritemid+1]->data,PR_MAX_DATA_LEN,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEMid)))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_TAIL & wpset) != 0) && !(picokpr_isEqualTail(with__0->rnetwork,pr->ritems[with__0->ritemid+1]->data,PR_MAX_DATA_LEN,pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSETail)))) { + return PR_MSNotMatched; + } + } + if (((PR_TSE_MASK_AUC & npset) != 0) && !(pr->ritems[with__0->ritemid+1]->auc)) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_ALC & npset) != 0) && !(pr->ritems[with__0->ritemid+1]->alc)) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_SUC & npset) != 0) && !(pr->ritems[with__0->ritemid+1]->suc)) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_ROMAN & npset) != 0) && !(pr_isLatinNumber(pr->ritems[with__0->ritemid+1]->data,& lromanval))) { + return PR_MSNotMatched; + } + if (((PR_TSE_MASK_ID & wpset) != 0) && (pr->ritems[with__0->ritemid+1]->head.info2 != pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEID))) { + return PR_MSNotMatched; + } + return PR_MSMatched; +} + + +static pr_MatchState pr_matchTokensBegin (picodata_ProcessingUnit this, pr_subobj_t * pr, + picokpr_TokSetNP npset, picokpr_TokSetWP wpset) +{ + npset = npset; /* avoid warning "var not used in this function"*/ + wpset = wpset; /* avoid warning "var not used in this function"*/ + if ((PR_TSE_MASK_BEGIN &picokpr_getTokSetNP(pr->ractpath.rele[pr->ractpath.rlen - 1].rnetwork, pr->ractpath.rele[pr->ractpath.rlen - 1].rtok)) != 0) { + return PR_MSMatched; + } else { + return PR_MSNotMatched; + } +} + + + +static pr_MatchState pr_matchTokensEnd (picodata_ProcessingUnit this, pr_subobj_t * pr, + picokpr_TokSetNP npset, picokpr_TokSetWP wpset) +{ + npset = npset; /* avoid warning "var not used in this function"*/ + wpset = wpset; /* avoid warning "var not used in this function"*/ + if ((PR_TSE_MASK_END &picokpr_getTokSetNP(pr->ractpath.rele[pr->ractpath.rlen - 1].rnetwork, pr->ractpath.rele[pr->ractpath.rlen - 1].rtok)) != 0) { + return PR_MSMatched; + } else { + return PR_MSNotMatched; + } +} + + +static pr_MatchState pr_matchTokens (picodata_ProcessingUnit this, pr_subobj_t * pr, picoos_int16 * cmpres) +{ + + register struct pr_PathEle * with__0; + picokpr_VarStrPtr lstrp; + picokpr_TokSetNP npset; + picokpr_TokSetWP wpset; + + with__0 = & pr->ractpath.rele[pr->ractpath.rlen - 1]; + npset = picokpr_getTokSetNP(with__0->rnetwork, with__0->rtok); + wpset = picokpr_getTokSetWP(with__0->rnetwork, with__0->rtok); + + *cmpres = PR_EQUAL; + if ((PR_TSE_MASK_STR & wpset) != 0) { + lstrp = picokpr_getVarStrPtr(with__0->rnetwork, pr_attrVal(with__0->rnetwork, with__0->rtok, PR_TSEStr)); + pr_compare(pr->ritems[with__0->ritemid+1]->strci,lstrp,cmpres); + } + if (((PR_TSE_MASK_LEX & wpset) == PR_TSE_MASK_LEX) && ((PR_TSE_MASK_LETTER & npset) == 0)) { + return pr_matchMultiToken(this, pr, npset, wpset); + } else { + switch (pr->ritems[with__0->ritemid+1]->head.info1) { + case PICODATA_ITEMINFO1_TOKTYPE_BEGIN: + return pr_matchTokensBegin(this, pr, npset, wpset); + break; + case PICODATA_ITEMINFO1_TOKTYPE_END: + return pr_matchTokensEnd(this, pr, npset, wpset); + break; + case PICODATA_ITEMINFO1_TOKTYPE_SPACE: + return pr_matchTokensSpace(this, pr, *cmpres, npset, wpset); + break; + case PICODATA_ITEMINFO1_TOKTYPE_DIGIT: + return pr_matchTokensDigit(this, pr, *cmpres, npset, wpset); + break; + case PICODATA_ITEMINFO1_TOKTYPE_LETTER: + return pr_matchTokensLetter(this, pr, *cmpres, npset, wpset); + break; + case PICODATA_ITEMINFO1_TOKTYPE_SEQ: + return pr_matchTokensSeq(this, pr, *cmpres, npset, wpset); + break; + case PICODATA_ITEMINFO1_TOKTYPE_CHAR: + return pr_matchTokensChar(this, pr, *cmpres, npset, wpset); + break; + default: + PICODBG_INFO(("pr_matchTokens: unknown token type")); + return PR_MSNotMatched; + break; + } + } +} + + +static void pr_calcPathCost (struct pr_Path * path) +{ + picoos_int32 li; + picoos_bool lfirst; + picokpr_TokSetWP wpset; + picokpr_TokSetNP npset; +#if PR_TRACE_PATHCOST + picoos_uchar str[1000]; + picoos_uchar * strp; +#endif + +#if PR_TRACE_PATHCOST + str[0] = 0; +#endif + + lfirst = TRUE; + path->rcost = PR_COST_INIT; + for (li = 0; li < path->rlen; li++) { + if (li == 0) { + path->rcost = path->rcost + path->rele[li].rprodprefcost; + } + wpset = picokpr_getTokSetWP(path->rele[li].rnetwork, path->rele[li].rtok); + npset = picokpr_getTokSetNP(path->rele[li].rnetwork, path->rele[li].rtok); + if ((PR_TSE_MASK_COST & wpset) != 0) { + if (((PR_TSE_MASK_LEX & wpset) == PR_TSE_MASK_LEX) && ((PR_TSE_MASK_LETTER & npset) == 0)) { + if (lfirst) { + path->rcost = path->rcost - PR_COST + pr_attrVal(path->rele[li].rnetwork, path->rele[li].rtok, PR_TSECost); + } else { + path->rcost = path->rcost - PR_COST; + } + lfirst = FALSE; + } else { + path->rcost = path->rcost - PR_COST + pr_attrVal(path->rele[li].rnetwork, path->rele[li].rtok, PR_TSECost); + lfirst = TRUE; + } + } else if (pr_hasToken(& wpset,& npset)) { + path->rcost = path->rcost - PR_COST; + } +#if PR_TRACE_PATHCOST + if ((path->rele[li].rprodname != 0)) { + strp = picokpr_getVarStrPtr(path->rele[li].rnetwork, path->rele[li].rprodname); + picoos_strcat(str, (picoos_char *)" "); + picoos_strcat(str, strp); + } +#endif + } +#if PR_TRACE_PATHCOST + PICODBG_INFO(("pp cost: %i %s", path->rcost, str)); +#endif +} + + +void pr_processToken (picodata_ProcessingUnit this, pr_subobj_t * pr) +{ + register struct pr_PathEle * with__0; + picoos_bool ldummy; + picoos_int32 li; + picokpr_TokSetNP npset; + picokpr_TokSetWP wpset; + + do { + pr->rgState = PR_GSContinue; + if (pr->ractpath.rlen == 0) { + if (pr_getTopLevelToken(this, pr, FALSE)) { + pr->rgState = PR_GSContinue; + } else if (pr->rbestpath.rlen == 0) { + pr->rgState = PR_GSNotFound; + } else { + pr->rgState = PR_GSFound; + } + } else { + if (pr->maxPathLen < pr->ractpath.rlen) { + pr->maxPathLen = pr->ractpath.rlen; + } + with__0 = & pr->ractpath.rele[pr->ractpath.rlen - 1]; + switch (with__0->rlState) { + case PR_LSInit: + npset = picokpr_getTokSetNP(with__0->rnetwork, with__0->rtok); + wpset = picokpr_getTokSetWP(with__0->rnetwork, with__0->rtok); + if ((PR_TSE_MASK_ACCEPT & npset) != 0){ + if (with__0->rdepth == 1) { + pr_calcPathCost(&pr->ractpath); + if ((pr->rbestpath.rlen == 0) || (pr->ractpath.rcost < pr->rbestpath.rcost)) { + pr->rbestpath.rlen = pr->ractpath.rlen; + pr->rbestpath.rcost = pr->ractpath.rcost; + for (li = 0; li < pr->ractpath.rlen; li++) { + pr->rbestpath.rele[li] = pr->ractpath.rele[li]; + } + } + with__0->rlState = PR_LSGetNextToken; + } else { + with__0->rlState = PR_LSGetProdContToken; + } + } else if ((PR_TSE_MASK_PROD & wpset) != 0) { + with__0->rlState = PR_LSGetProdToken; + } else if ((PR_TSE_MASK_OUT & wpset) != 0) { + with__0->rlState = PR_LSGetNextToken; + } else if (pr_hasToken(& wpset,& npset)) { + with__0->rlState = PR_LSGetToken; + } else { + with__0->rlState = PR_LSGetNextToken; + } + break; + case PR_LSGetProdToken: + with__0->rlState = PR_LSGetAltToken; + ldummy = pr_getProdToken(this, pr); + break; + case PR_LSGetProdContToken: + with__0->rlState = PR_LSGetAltToken; + ldummy = pr_getProdContToken(this, pr); + break; + case PR_LSGoBack: + pr->ractpath.rlen--; + break; + case PR_LSGetToken: + if (pr_getToken(this, pr)) { + with__0->rlState = PR_LSMatch; + } else if (pr->forceOutput) { + with__0->rlState = PR_LSGetAltToken; + } else { + with__0->rlState = PR_LSGetToken2; + pr->rgState = PR_GSNeedToken; + } + break; + case PR_LSGetToken2: + if (pr_getToken(this, pr)) { + with__0->rlState = PR_LSMatch; + } else { + with__0->rlState = PR_LSGoBack; + } + break; + case PR_LSMatch: + switch (pr_matchTokens(this, pr, & with__0->rcompare)) { + case PR_MSMatched: + with__0->rlState = PR_LSGetNextToken; + break; + case PR_MSMatchedContinue: + with__0->rlState = PR_LSGetAltToken; + ldummy = pr_getNextMultiToken(this, pr); + break; + case PR_MSMatchedMulti: + with__0->rlState = PR_LSGetNextToken; + ldummy = pr_getNextMultiToken(this, pr); + break; + default: + with__0->rlState = PR_LSGetAltToken; + break; + } + break; + case PR_LSGetNextToken: + with__0->rlState = PR_LSGetAltToken; + ldummy = pr_getNextToken(this, pr); + break; + case PR_LSGetAltToken: + with__0->rlState = PR_LSGoBack; + ldummy = pr_getAltToken(this, pr); + break; + default: + PICODBG_INFO(("unhandled local state")); + break; + } + } + pr->nrIterations--; + } while ((pr->rgState == PR_GSContinue) && (pr->nrIterations > 0)); +} + + +void pr_process (picodata_ProcessingUnit this, pr_subobj_t * pr) +{ + switch (pr->rgState) { + case PR_GS_START: + case PR_GSFound: + case PR_GSNotFound: + pr->ractpath.rlen = 0; + pr->ractpath.rcost = PR_COST_INIT; + pr->rbestpath.rlen = 0; + pr->rbestpath.rcost = PR_COST_INIT; + if (pr_getTopLevelToken(this, pr, TRUE)) { + pr->rgState = PR_GSContinue; + } else { + pr->rgState = PR_GSNotFound; + } + break; + case PR_GSContinue: + pr_processToken(this, pr); + break; + case PR_GSNeedToken: + pr->rgState = PR_GSContinue; + break; + default: + pr->rgState = PR_GS_START; + break; + } +} + + +static void pr_prepareItem (picodata_ProcessingUnit this, pr_subobj_t * pr, pr_ioItemPtr item) +{ + pr->ritems[pr->rnritems + 1] = item; + pr->rnritems++; +} + + +static void pr_processItems (picodata_ProcessingUnit this, pr_subobj_t * pr) +{ + pr_ioItemPtr lit; + pr_MemState lmemState; + + pr_getMemState(this, pr_WorkMem,& lmemState); + + while ((pr->rinItemList != NULL) && (pr->rinItemList->head.type != PICODATA_ITEM_TOKEN)) { + lit = pr->rinItemList; + PICODBG_INFO(("pp in (0)")); + PICODBG_INFO(("pp out(0)")); + pr->rinItemList = pr->rinItemList->next; + lit->next = NULL; + if (pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_PHONEME) && pr_isCmdInfo2(lit, PICODATA_ITEMINFO2_CMD_START)) { + pr->insidePhoneme = TRUE; + } else if (pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_PHONEME) && pr_isCmdInfo2(lit, PICODATA_ITEMINFO2_CMD_END)) { + pr->insidePhoneme = FALSE; + } + if (pr->insidePhoneme && (pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_PLAY) || pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_IGNSIG))) { + pr_disposeItem(this, & lit); + } else if (pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_CONTEXT)) { + pr_setContext(this, pr, lit->data); + pr_disposeItem(this, & lit); + } else if (pr->rignore <= 0) { + pr_appendItemToOutItemList(this, pr, & pr->routItemList,& pr->rlastOutItem,lit); + if (pr->outOfMemory) return; + } else { + pr_disposeItem(this, & lit); + } + pr->rgState = PR_GS_START; + } + if (pr->rinItemList != NULL) { + pr_process(this, pr); + if (pr->rgState == PR_GSNotFound) { + lit = pr->rinItemList; + pr->rinItemList = pr->rinItemList->next; + lit->next = NULL; + PICODBG_INFO(("pp in (2): '%s'", lit->data)); + if (pr->rignore <= 0) { + PICODBG_INFO(("pp out(2): '%s'", lit->data)); + } + + if (pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_PHONEME) && pr_isCmdInfo2(lit, PICODATA_ITEMINFO2_CMD_START)) { + pr->insidePhoneme = TRUE; + } else if (pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_PHONEME) && pr_isCmdInfo2(lit, PICODATA_ITEMINFO2_CMD_END)) { + pr->insidePhoneme = FALSE; + } + if (((pr->rignore <= 0) && !((pr->insidePhoneme && (pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_PLAY) || pr_isCmdType(lit,PICODATA_ITEMINFO1_CMD_IGNSIG)))))) { + pr_appendItemToOutItemList(this, pr, & pr->routItemList,& pr->rlastOutItem,lit); + if (pr->outOfMemory) return; + } else { + pr_disposeItem(this, & lit); + } + pr->rgState = PR_GS_START; + pr->rnritems = 0; + } else if (pr->rgState == PR_GSFound) { + pr_outputPath(this, pr); + if (pr->outOfMemory) return; + pr->rgState = PR_GS_START; + pr->rnritems = 0; + } + } + if (pr->rinItemList == NULL) { + pr->rlastInItem = NULL; + } else if (pr->rnritems == 0) { + lit = pr->rinItemList; + while (lit != NULL) { + if (lit->head.type == PICODATA_ITEM_TOKEN) { + pr_prepareItem(this, pr, lit); + } + lit = lit->next; + } + } + pr_resetMemState(this, pr_WorkMem,lmemState); +} + + + +extern void pr_treatItem (picodata_ProcessingUnit this, pr_subobj_t * pr, pr_ioItemPtr item) +{ + pr_ioItemPtr lit; + + pr_startItemList(& pr->routItemList,& pr->rlastOutItem); + + if (!PR_ENABLED || (pr->rgState == PR_GSNoPreproc)) { + /* preprocessing disabled or no preproc networks available: + append items directly to output item list */ + PICODBG_INFO(("pp in (3): '%s'", item->data)); + PICODBG_INFO(("pp out(3): '%s'", item->data)); + pr_appendItemToOutItemList(this, pr, & pr->routItemList,& pr->rlastOutItem,item); + } else { + + if (pr->actCtxChanged) { + pr->rgState = PR_GS_START; + pr->ractpath.rcost = PR_COST_INIT; + pr->ractpath.rlen = 0; + pr->rbestpath.rcost = PR_COST_INIT; + pr->rbestpath.rlen = 0; + pr->prodList = NULL; + pr->rnritems = 0; + pr->actCtxChanged = FALSE; + } + if (pr_isCmdType(item , PICODATA_ITEMINFO1_CMD_CONTEXT) || pr_isCmdType(item, PICODATA_ITEMINFO1_CMD_FLUSH)) { + /* context switch or flush: force processing and empty input item list */ + pr->forceOutput = TRUE; + } + pr_appendItem(this, & pr->rinItemList,& pr->rlastInItem, item); + if (pr->rnritems == 0) { + lit = pr->rinItemList; + while (lit != NULL) { + if (lit->head.type == PICODATA_ITEM_TOKEN) { + pr_prepareItem(this, pr, lit); + } + lit = lit->next; + } + } else if (item->head.type == PICODATA_ITEM_TOKEN) { + pr_prepareItem(this, pr, item); + } + } +} + +/* *****************************************************************************/ +/* *****************************************************************************/ +/* *****************************************************************************/ + + +pico_status_t prReset(register picodata_ProcessingUnit this, picoos_int32 resetMode) +{ + + picoos_int32 i; + pr_subobj_t * pr; + + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + pr = (pr_subobj_t *) this->subObj; + + pr->rinItemList = NULL; + pr->rlastInItem = NULL; + pr->routItemList = NULL; + pr->rlastOutItem = NULL; + pr->ractpath.rcost = PR_COST_INIT; + pr->ractpath.rlen = 0; + pr->rbestpath.rcost = PR_COST_INIT; + pr->rbestpath.rlen = 0; + pr->rnritems = 0; + pr->ritems[0] = NULL; + pr->rignore = 0; + pr->spellMode = 0; + pr->maxPathLen = 0; + pr->insidePhoneme = FALSE; + pr->saveFile[0] = 0; + + pr->outReadPos = 0; + pr->outWritePos = 0; + pr->inBufLen = 0; + + pr->rgState = PR_GSNoPreproc; + for (i=0; ipreproc[i] != NULL) { + pr->rgState = PR_GS_START; + } + } + pr->actCtx = pr_findContext(pr->ctxList, (picoos_uchar*)PICO_CONTEXT_DEFAULT); + pr->actCtxChanged = FALSE; + pr->prodList = NULL; + + if (((uintptr_t)pr->pr_WorkMem % PICOOS_ALIGN_SIZE) == 0) { + pr->workMemTop = 0; + } + else { + pr->workMemTop = PICOOS_ALIGN_SIZE - ((uintptr_t)pr->pr_WorkMem % PICOOS_ALIGN_SIZE); + } + pr->maxWorkMemTop=0; + pr->dynMemSize=0; + pr->maxDynMemSize=0; + /* this is ok to be in 'initialize' because it is a private memory within pr. Creating a new mm + * here amounts to resetting this internal memory + */ + pr->dynMemMM = picoos_newMemoryManager((void *)pr->pr_DynMem, PR_DYN_MEM_SIZE, + /*enableMemProt*/ FALSE); + pr->outOfMemory = FALSE; + + pr->forceOutput = FALSE; + + if (resetMode == PICO_RESET_SOFT) { + /*following initializations needed only at startup or after a full reset*/ + return PICO_OK; + } + + pr->xsampa_parser = picokfst_getFST(this->voice->kbArray[PICOKNOW_KBID_FST_XSAMPA_PARSE]); + + pr->svoxpa_parser = picokfst_getFST(this->voice->kbArray[PICOKNOW_KBID_FST_SVOXPA_PARSE]); + + pr->xsampa2svoxpa_mapper = picokfst_getFST(this->voice->kbArray[PICOKNOW_KBID_FST_XSAMPA2SVOXPA]); + + + + return PICO_OK; +} + + +pico_status_t prInitialize(register picodata_ProcessingUnit this, picoos_int32 resetMode) +{ +/* + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } +*/ + return prReset(this, resetMode); +} + + +pico_status_t prTerminate(register picodata_ProcessingUnit this) +{ + return PICO_OK; +} + +picodata_step_result_t prStep(register picodata_ProcessingUnit this, picoos_int16 mode, picoos_uint16 * numBytesOutput); + +pico_status_t prSubObjDeallocate(register picodata_ProcessingUnit this, + picoos_MemoryManager mm) +{ + pr_subobj_t * pr; + + if (NULL != this) { + pr = (pr_subobj_t *) this->subObj; + mm = mm; /* avoid warning "var not used in this function"*/ + PICODBG_INFO(("max pr_WorkMem: %i of %i", pr->maxWorkMemTop, PR_WORK_MEM_SIZE)); + PICODBG_INFO(("max pr_DynMem: %i of %i", pr->maxDynMemSize, PR_DYN_MEM_SIZE)); + + pr_disposeContextList(this); + picoos_deallocate(this->common->mm, (void *) &this->subObj); + } + return PICO_OK; +} + +picodata_ProcessingUnit picopr_newPreprocUnit(picoos_MemoryManager mm, picoos_Common common, + picodata_CharBuffer cbIn, picodata_CharBuffer cbOut, + picorsrc_Voice voice) +{ + picoos_int32 i; + pr_subobj_t * pr; + + + picodata_ProcessingUnit this = picodata_newProcessingUnit(mm, common, cbIn, cbOut, voice); + if (this == NULL) { + return NULL; + } + + this->initialize = prInitialize; + PICODBG_DEBUG(("set this->step to prStep")); + this->step = prStep; + this->terminate = prTerminate; + this->subDeallocate = prSubObjDeallocate; + this->subObj = picoos_allocate(mm, sizeof(pr_subobj_t)); +#if PR_TRACE_MEM || PR_TRACE_MAX_MEM + PICODBG_INFO(("preproc alloc: %i", sizeof(pr_subobj_t))); + PICODBG_INFO(("max dyn size: %i", PR_MAX_PATH_LEN*((((PR_IOITEM_MIN_SIZE+2) + PICOOS_ALIGN_SIZE - 1) / PICOOS_ALIGN_SIZE) * PICOOS_ALIGN_SIZE + 16))); +#endif + if (this->subObj == NULL) { + picoos_deallocate(mm, (void *)&this); + return NULL; + } + pr = (pr_subobj_t *) this->subObj; + + pr->graphs = picoktab_getGraphs(this->voice->kbArray[PICOKNOW_KBID_TAB_GRAPHS]); + pr->preproc[0] = picokpr_getPreproc(this->voice->kbArray[PICOKNOW_KBID_TPP_MAIN]); + for (i=0; ipreproc[1+i] = picokpr_getPreproc(this->voice->kbArray[PICOKNOW_KBID_TPP_USER_1+i]); + } + + if (pr_createContextList(this) != PICO_OK) { + pr_disposeContextList(this); + picoos_deallocate(mm, (void *)&this); + return NULL; + } + prInitialize(this, PICO_RESET_FULL); + return this; +} + +/** + * fill up internal buffer + */ +picodata_step_result_t prStep(register picodata_ProcessingUnit this, + picoos_int16 mode, picoos_uint16 * numBytesOutput) +{ + register pr_subobj_t * pr; + pr_ioItemPtr it; + picoos_int32 len, i; + pico_status_t rv; + picoos_int32 id; + picoos_uint8 info1; + picoos_uint8 info2; + picoos_int32 nrUtfChars; + picoos_uint32 pos; + picobase_utf8char inUtf8char, outUtf8char; + picoos_int32 inUtf8charlen, outUtf8charlen; + picoos_int32 lenpos; + picoos_bool ldone; + picoos_bool split; + + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + pr = (pr_subobj_t *) this->subObj; + + if (pr->outOfMemory) return PICODATA_PU_ERROR; + + mode = mode; /* avoid warning "var not used in this function"*/ + pr->nrIterations = PR_MAX_NR_ITERATIONS; + + *numBytesOutput = 0; + while (1) { /* exit via return */ + if ((pr->outWritePos - pr->outReadPos) > 0) { + /* deliver the data in the output buffer */ + if (picodata_cbPutItem(this->cbOut, &pr->outBuf[pr->outReadPos], pr->outWritePos - pr->outReadPos, numBytesOutput) == PICO_OK) { + pr->outReadPos += *numBytesOutput; + if (pr->outWritePos == pr->outReadPos) { + pr->outWritePos = 0; + pr->outReadPos = 0; + } + } + else { + return PICODATA_PU_OUT_FULL; + } + } + else if (pr->routItemList != NULL) { + /* there are item(s) in the output item list, move them to the output buffer */ + it = pr->routItemList; + pr->routItemList = pr->routItemList->next; + if (pr->routItemList == NULL) { + pr->rlastOutItem = NULL; + } + if (it->head.type == PICODATA_ITEM_TOKEN) { + if ((it->head.info1 != PICODATA_ITEMINFO1_TOKTYPE_SPACE) && (it->head.len > 0)) { + nrUtfChars = picobase_utf8_length(it->data, PR_MAX_DATA_LEN); + if ((nrUtfChars == 1) + && (((id = picoktab_graphOffset(pr->graphs, it->data)) > 0)) + && picoktab_getIntPropPunct(pr->graphs, id, &info1, &info2)) { + /* single punctuation chars have to be delivered as PICODATA_ITEM_PUNC items + instead as PICODATA_ITEM_WORDGRAPH items */ + pr->outBuf[pr->outWritePos++] = PICODATA_ITEM_PUNC; + pr->outBuf[pr->outWritePos++] = info1; + pr->outBuf[pr->outWritePos++] = info2; + pr->outBuf[pr->outWritePos++] = 0; + PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG], + (picoos_uint8 *)"pr: ", pr->outBuf, pr->outWritePos); + } + else { + /* do subgraphs substitutions and deliver token items as PICODATA_ITEM_WORDGRAPH + items to the output buffer */ + split = FALSE; + pr->outBuf[pr->outWritePos++] = PICODATA_ITEM_WORDGRAPH; + pr->outBuf[pr->outWritePos++] = PICODATA_ITEMINFO1_NA; + pr->outBuf[pr->outWritePos++] = PICODATA_ITEMINFO2_NA; + lenpos=pr->outWritePos; + pr->outBuf[pr->outWritePos++] = 0; + pos = 0; + len = pr_strlen(it->data); + while (pos < (picoos_uint32)len) { + if (picobase_get_next_utf8char(it->data, it->head.len, &pos, inUtf8char)) { + if (inUtf8char[0] <= 32) { + /* do not add whitespace characters to the output buffer, + but initiate token splitting instead + + */ + split = TRUE; + } + else if (((id = picoktab_graphOffset(pr->graphs, inUtf8char)) > 0) && picoktab_getStrPropGraphsubs1(pr->graphs, id, outUtf8char)) { + if (split) { + /* split the token, eg. start a new item */ + pr->outBuf[pr->outWritePos++] = PICODATA_ITEM_WORDGRAPH; + pr->outBuf[pr->outWritePos++] = PICODATA_ITEMINFO1_NA; + pr->outBuf[pr->outWritePos++] = PICODATA_ITEMINFO2_NA; + lenpos=pr->outWritePos; + pr->outBuf[pr->outWritePos++] = 0; + } + outUtf8charlen = picobase_det_utf8_length(outUtf8char[0]); + for (i=0; ioutBuf[pr->outWritePos++] = outUtf8char[i]; + pr->outBuf[lenpos]++; + } + if (picoktab_getStrPropGraphsubs2(pr->graphs, id, outUtf8char)) { + outUtf8charlen = picobase_det_utf8_length(outUtf8char[0]); + for (i=0; ioutBuf[pr->outWritePos++] = outUtf8char[i]; + pr->outBuf[lenpos]++; + } + } + split = FALSE; + } + else { + if (split) { + /* split the token, eg. start a new item */ + pr->outBuf[pr->outWritePos++] = PICODATA_ITEM_WORDGRAPH; + pr->outBuf[pr->outWritePos++] = PICODATA_ITEMINFO1_NA; + pr->outBuf[pr->outWritePos++] = PICODATA_ITEMINFO2_NA; + lenpos=pr->outWritePos; + pr->outBuf[pr->outWritePos++] = 0; + } + inUtf8charlen = picobase_det_utf8_length(inUtf8char[0]); + for (i=0; ioutBuf[pr->outWritePos++] = inUtf8char[i]; + pr->outBuf[lenpos]++; + } + split = FALSE; + } + } + } + PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG], + (picoos_uint8 *)"pr: ", pr->outBuf, pr->outWritePos); + } + } + } + else { + /* handle all other item types and put them to the output buffer */ + pr->outBuf[pr->outWritePos++] = it->head.type; + pr->outBuf[pr->outWritePos++] = it->head.info1; + pr->outBuf[pr->outWritePos++] = it->head.info2; + pr->outBuf[pr->outWritePos++] = it->head.len; + for (i=0; ihead.len; i++) { + pr->outBuf[pr->outWritePos++] = it->data[i]; + } + PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG], + (picoos_uint8 *)"pr: ", pr->outBuf, pr->outWritePos); + } + pr_disposeItem(this, &it); + } + else if (pr->forceOutput) { + pr_processItems(this, pr); + if (pr->rinItemList == NULL) { + pr->forceOutput = FALSE; + } + } + else if ((pr->rgState != PR_GSNeedToken) && (pr->rinItemList != NULL)) { + pr_processItems(this, pr); + } + else if (pr->inBufLen > 0) { + /* input data is available in the input buffer, copy it to an input item + and treat it */ + if (pr->dynMemSize < (45*PR_DYN_MEM_SIZE / 100)) { + pr_newItem(this, pr_DynMem, &it, pr->inBuf[0], pr->inBuf[3], /*inItem*/TRUE); + if (pr->outOfMemory) return PICODATA_PU_ERROR; + it->head.type = pr->inBuf[0]; + it->head.info1 = pr->inBuf[1]; + it->head.info2 = pr->inBuf[2]; + it->head.len = pr->inBuf[3]; + for (i=0; iinBuf[3]; i++) { + it->data[i] = pr->inBuf[4+i]; + } + it->data[pr->inBuf[3]] = 0; + if ((pr->inBuf[0] == PICODATA_ITEM_TOKEN) && ((pr->inBuf[1] == PICODATA_ITEMINFO1_TOKTYPE_DIGIT))) { + it->val = tok_tokenDigitStrToInt(this, pr, it->data); + } else { + it->val = 0; + } + if (pr->inBuf[0] == PICODATA_ITEM_TOKEN) { + picobase_lowercase_utf8_str(it->data,it->strci,PR_MAX_DATA_LEN, &ldone); + pr_firstLetterToLowerCase(it->data,it->strcis); + it->alc = picobase_is_utf8_lowercase(it->data,PR_MAX_DATA_LEN); + it->auc = picobase_is_utf8_uppercase(it->data,PR_MAX_DATA_LEN); + it->suc = pr_isSUC(it->data); + } + + pr_treatItem(this, pr, it); + if (pr->outOfMemory) return PICODATA_PU_ERROR; + pr_processItems(this, pr); + pr->inBufLen = 0; + } + else { + pr->forceOutput = TRUE; + } + } + else { + /* there is not data in the output buffer and there is no data in the output item list, so + check whether input data is available */ + rv = picodata_cbGetItem(this->cbIn, pr->inBuf, IN_BUF_SIZE+PICODATA_ITEM_HEADSIZE, &pr->inBufLen); + if (PICO_OK == rv) { + } else if (PICO_EOF == rv) { + /* there was no item in the char buffer */ + return PICODATA_PU_IDLE; + } else if ((PICO_EXC_BUF_UNDERFLOW == rv) || (PICO_EXC_BUF_OVERFLOW == rv)) { + pr->inBufLen = 0; + PICODBG_ERROR(("problem getting item")); + picoos_emRaiseException(this->common->em, rv, NULL, NULL); + return PICODATA_PU_ERROR; + } else { + pr->inBufLen = 0; + PICODBG_ERROR(("problem getting item, unhandled")); + picoos_emRaiseException(this->common->em, rv, NULL, NULL); + return PICODATA_PU_ERROR; + } + } +#if PR_TRACE_MEM + PICODBG_INFO(("memory: dyn=%u, work=%u", pr->dynMemSize, pr->workMemTop)); +#endif + if (pr->nrIterations <= 0) { + return PICODATA_PU_BUSY; + } + } /* while */ + return PICODATA_PU_ERROR; +} + +#ifdef __cplusplus +} +#endif + + + +/* end */ diff --git a/pico/lib/picopr.h b/pico/lib/picopr.h new file mode 100644 index 0000000..3ade5c9 --- /dev/null +++ b/pico/lib/picopr.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picopr.h + * + * text preprocessor PU - include file + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ +/** + * @addtogroup picopr + * + * Text Pre Processing module \n + * +*/ +#ifndef PICOPR_H_ +#define PICOPR_H_ + +#include "picoos.h" +#include "picodata.h" +#include "picorsrc.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +picodata_ProcessingUnit picopr_newPreprocUnit( + picoos_MemoryManager mm, + picoos_Common common, + picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, + picorsrc_Voice voice); + +#define PICOPR_OUTBUF_SIZE 256 + +#ifdef __cplusplus +} +#endif + + +#endif /*PICOPR_H_*/ diff --git a/pico/lib/picorsrc.c b/pico/lib/picorsrc.c new file mode 100644 index 0000000..d8976b2 --- /dev/null +++ b/pico/lib/picorsrc.c @@ -0,0 +1,1028 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picorsrc.c + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include "picodefs.h" +#include "picoos.h" +#include "picodbg.h" + +/* knowledge layer */ +#include "picoknow.h" + +#include "picokdt.h" +#include "picoklex.h" +#include "picokfst.h" +#include "picokpdf.h" +#include "picoktab.h" +#include "picokpr.h" + +#include "picorsrc.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +#if defined(PICO_DEBUG) +#include "picokdbg.h" +#endif + + +/** object : Resource + * shortcut : rsrc + * + */ +typedef struct picorsrc_resource { + picoos_uint32 magic; /* magic number used to validate handles */ + /* next connects all active resources of a resource manager and the garbaged resources of the manager's free list */ + picorsrc_Resource next; + picorsrc_resource_type_t type; + picorsrc_resource_name_t name; + picoos_int8 lockCount; /* count of current subscribers of this resource */ + picoos_File file; + picoos_uint8 * raw_mem; /* pointer to allocated memory. NULL if preallocated. */ + /* picoos_uint32 size; */ + picoos_uint8 * start; /* start of content (after header) */ + picoknow_KnowledgeBase kbList; +} picorsrc_resource_t; + + +#define MAGIC_MASK 0x7049634F /* pIcO */ + +#define SET_MAGIC_NUMBER(res) \ + (res)->magic = ((picoos_uint32) (uintptr_t) (res)) ^ MAGIC_MASK + +#define CHECK_MAGIC_NUMBER(res) \ + ((res)->magic == (((picoos_uint32) (uintptr_t) (res)) ^ MAGIC_MASK)) + + + +/** + * Returns non-zero if 'this' is a valid resource handle, zero otherwise. + */ +picoos_int16 picoctrl_isValidResourceHandle(picorsrc_Resource this) +{ + return (this != NULL) && CHECK_MAGIC_NUMBER(this); +} + + +static picorsrc_Resource picorsrc_newResource(picoos_MemoryManager mm) +{ + picorsrc_Resource this = picoos_allocate(mm, sizeof(*this)); + if (NULL != this) { + SET_MAGIC_NUMBER(this); + /* initialize */ + this->name[0] = NULLC; + /* picoos_strlcpy(this->name, name,PICORSRC_MAX_RSRC_NAME_SIZ); */ + this->next = NULL; + this->type = PICORSRC_TYPE_NULL; + this->lockCount = 0; + this->file = NULL; + this->raw_mem = NULL; + this->start = NULL; + this->kbList = NULL; + /* this->size=0; */ + } + return this; +} + +static void picorsrc_disposeResource(picoos_MemoryManager mm, picorsrc_Resource * this) +{ + if (NULL != (*this)) { + (*this)->magic ^= 0xFFFEFDFC; + /* we have to explicitly free 'raw_mem' here because in testing + scenarios (where memory protection functionality is enabled) + it might be allocated aside from normal memory */ + if ((*this)->raw_mem != NULL) { + picoos_deallocProtMem(mm, (void *) &(*this)->raw_mem); + } + picoos_deallocate(mm,(void * *)this); + } +} + + + + +static void picorsrc_initializeVoice(picorsrc_Voice this) +{ + picoos_uint16 i; + if (NULL != this) { + /* initialize */ + for (i=0; ikbArray[i] = NULL; + } + this->numResources = 0; + this->next = NULL; + } +} + +static picorsrc_Voice picorsrc_newVoice(picoos_MemoryManager mm) +{ + picorsrc_Voice this = (picorsrc_Voice) picoos_allocate(mm,sizeof(*this)); + picorsrc_initializeVoice(this); + return this; +} + +/* +static void picorsrc_disposeVoice(picoos_MemoryManager mm, picorsrc_Voice * this) +{ + if (NULL != (*this)) { + + picoos_deallocate(mm,(void *)this); + } +} +*/ + + +/** object : VoiceDefinition + * shortcut : vdef + * + */ + +typedef struct picorsrc_voice_definition * picorsrc_VoiceDefinition; + +typedef struct picorsrc_voice_definition { + picoos_char voiceName[PICO_MAX_VOICE_NAME_SIZE]; + picoos_uint8 numResources; + picorsrc_resource_name_t resourceName[PICO_MAX_NUM_RSRC_PER_VOICE]; + picorsrc_VoiceDefinition next; +} picorsrc_voice_definition_t; + + +static picorsrc_VoiceDefinition picorsrc_newVoiceDefinition(picoos_MemoryManager mm) +{ + /* picoos_uint8 i; */ + picorsrc_VoiceDefinition this = (picorsrc_VoiceDefinition) picoos_allocate(mm,sizeof(*this)); + if (NULL != this) { + /* initialize */ + this->voiceName[0] = NULLC; + this->numResources = 0; + /* + for (i=0; i < PICO_MAX_NUM_RSRC_PER_VOICE; i++) { + this->resourceName[i][0] = NULLC; + } + */ + this->next = NULL; + } + return this; +} + +/* +static void picorsrc_disposeVoiceDefinition(picoos_MemoryManager mm, picorsrc_VoiceDefinition * this) +{ + if (NULL != (*this)) { + + picoos_deallocate(mm,(void *)this); + } +} +*/ + + + +/** object : ResourceManager + * shortcut : rm + * + */ +typedef struct picorsrc_resource_manager { + picoos_Common common; + picoos_uint16 numResources; + picorsrc_Resource resources, freeResources; + picoos_uint16 numVoices; + picorsrc_Voice voices, freeVoices; + picoos_uint16 numVdefs; + picorsrc_VoiceDefinition vdefs, freeVdefs; + picoos_uint16 numKbs; + picoknow_KnowledgeBase freeKbs; + picoos_header_string_t tmpHeader; +} picorsrc_resource_manager_t; + +pico_status_t picorsrc_createDefaultResource(picorsrc_ResourceManager this /*, + picorsrc_Resource * resource */); + + +picorsrc_ResourceManager picorsrc_newResourceManager(picoos_MemoryManager mm, picoos_Common common /* , picoos_char * configFile */) +{ + picorsrc_ResourceManager this = picoos_allocate(mm,sizeof(*this)); + if (NULL != this) { + /* initialize */ + this->common = common; + this->numResources = 0; + this->resources = NULL; + this->freeResources = NULL; + this->numVoices = 0; + this->voices = NULL; + this->freeVoices = NULL; + this->numVdefs = 0; + this->vdefs = NULL; + this->freeVdefs = NULL; + } + return this; +} + +void picorsrc_disposeResourceManager(picoos_MemoryManager mm, picorsrc_ResourceManager * this) +{ + if (NULL != (*this)) { + /* terminate */ + picoos_deallocate(mm,(void *)this); + } +} + + +/* ******* accessing resources **************************************/ + + +static pico_status_t findResource(picorsrc_ResourceManager this, picoos_char * resourceName, picorsrc_Resource * rsrc) { + picorsrc_Resource r; + if (NULL == this) { + return PICO_ERR_NULLPTR_ACCESS; + } + r = this->resources; + while (NULL != r && (0 != picoos_strcmp(r->name,resourceName))) { + r = r->next; + } + *rsrc = r; + return PICO_OK; +} + +static picoos_uint8 isResourceLoaded(picorsrc_ResourceManager this, picoos_char * resourceName) { + picorsrc_Resource res; + + if (PICO_OK == findResource(this, resourceName,&res)){ + return (NULL != res); + } else { + return FALSE; + } + } + +static pico_status_t parse_resource_name(picoos_char * fileName) +{ + PICODBG_DEBUG(("analysing file name %s",fileName)); + if (picoos_has_extension(fileName, + (picoos_char *)PICO_BIN_EXTENSION)) { + return PICO_OK; + } else { + return PICO_EXC_UNEXPECTED_FILE_TYPE; + } +} + + + +static pico_status_t readHeader(picorsrc_ResourceManager this, + picoos_FileHeader header, picoos_uint32 * headerlen, picoos_File file) +{ + + picoos_uint16 hdrlen1; + picoos_uint32 n; + pico_status_t status; + + + /* read PICO header */ + status = picoos_readPicoHeader(file, headerlen); + if (PICO_OK == status) { + + } else { + return picoos_emRaiseException(this->common->em,status,NULL,(picoos_char *)"problem reading file header"); + } + /* read header length (excluding length itself) */ + status = picoos_read_pi_uint16(file,&hdrlen1); + PICODBG_DEBUG(("got header size %d",hdrlen1)); + + if (PICO_OK == status) { + *headerlen += 2; + status = (hdrlen1 <= PICOOS_MAX_HEADER_STRING_LEN-1) ? PICO_OK : PICO_ERR_OTHER; + if (PICO_OK == status) { + n = hdrlen1; + if (picoos_ReadBytes(file, (picoos_uint8 *) this->tmpHeader, &n) && hdrlen1 == n) { + this->tmpHeader[hdrlen1] = NULLC; + *headerlen += hdrlen1; + PICODBG_DEBUG(("got header <%s>",this->tmpHeader)); + + status = PICO_OK; + } else { + status = PICO_ERR_OTHER; + } + } + if (PICO_OK == status) { + status = picoos_hdrParseHeader(header, this->tmpHeader); + } + } + return status; +} + +static pico_status_t picorsrc_createKnowledgeBase( + picorsrc_ResourceManager this, + picoos_uint8 * data, + picoos_uint32 size, + picoknow_kb_id_t kbid, + picoknow_KnowledgeBase * kb) +{ + (*kb) = picoknow_newKnowledgeBase(this->common->mm); + if (NULL == (*kb)) { + return PICO_EXC_OUT_OF_MEM; + } + (*kb)->base = data; + (*kb)->size = size; + (*kb)->id = kbid; + switch (kbid) { + case PICOKNOW_KBID_TPP_MAIN: + case PICOKNOW_KBID_TPP_USER_1: + case PICOKNOW_KBID_TPP_USER_2: + return picokpr_specializePreprocKnowledgeBase(*kb, this->common); + break; + case PICOKNOW_KBID_TAB_GRAPHS: + return picoktab_specializeGraphsKnowledgeBase(*kb, this->common); + break; + case PICOKNOW_KBID_TAB_PHONES: + return picoktab_specializePhonesKnowledgeBase(*kb, this->common); + break; + case PICOKNOW_KBID_TAB_POS: + return picoktab_specializePosKnowledgeBase(*kb, this->common); + break; + case PICOKNOW_KBID_FIXED_IDS: + return picoktab_specializeIdsKnowledgeBase(*kb, this->common); + break; + case PICOKNOW_KBID_LEX_MAIN: + case PICOKNOW_KBID_LEX_USER_1: + case PICOKNOW_KBID_LEX_USER_2: + return picoklex_specializeLexKnowledgeBase(*kb, this->common); + break; + case PICOKNOW_KBID_DT_POSP: + return picokdt_specializeDtKnowledgeBase(*kb, this->common, + PICOKDT_KDTTYPE_POSP); + break; + case PICOKNOW_KBID_DT_POSD: + return picokdt_specializeDtKnowledgeBase(*kb, this->common, + PICOKDT_KDTTYPE_POSD); + break; + case PICOKNOW_KBID_DT_G2P: + return picokdt_specializeDtKnowledgeBase(*kb, this->common, + PICOKDT_KDTTYPE_G2P); + break; + case PICOKNOW_KBID_DT_PHR: + return picokdt_specializeDtKnowledgeBase(*kb, this->common, + PICOKDT_KDTTYPE_PHR); + break; + case PICOKNOW_KBID_DT_ACC: + return picokdt_specializeDtKnowledgeBase(*kb, this->common, + PICOKDT_KDTTYPE_ACC); + break; + case PICOKNOW_KBID_FST_SPHO_1: + case PICOKNOW_KBID_FST_SPHO_2: + case PICOKNOW_KBID_FST_SPHO_3: + case PICOKNOW_KBID_FST_SPHO_4: + case PICOKNOW_KBID_FST_SPHO_5: + case PICOKNOW_KBID_FST_SPHO_6: + case PICOKNOW_KBID_FST_SPHO_7: + case PICOKNOW_KBID_FST_SPHO_8: + case PICOKNOW_KBID_FST_SPHO_9: + case PICOKNOW_KBID_FST_SPHO_10: + case PICOKNOW_KBID_FST_WPHO_1: + case PICOKNOW_KBID_FST_WPHO_2: + case PICOKNOW_KBID_FST_WPHO_3: + case PICOKNOW_KBID_FST_WPHO_4: + case PICOKNOW_KBID_FST_WPHO_5: + case PICOKNOW_KBID_FST_SVOXPA_PARSE: + case PICOKNOW_KBID_FST_XSAMPA_PARSE: + case PICOKNOW_KBID_FST_XSAMPA2SVOXPA: + + return picokfst_specializeFSTKnowledgeBase(*kb, this->common); + break; + + case PICOKNOW_KBID_DT_DUR: + case PICOKNOW_KBID_DT_LFZ1: + case PICOKNOW_KBID_DT_LFZ2: + case PICOKNOW_KBID_DT_LFZ3: + case PICOKNOW_KBID_DT_LFZ4: + case PICOKNOW_KBID_DT_LFZ5: + case PICOKNOW_KBID_DT_MGC1: + case PICOKNOW_KBID_DT_MGC2: + case PICOKNOW_KBID_DT_MGC3: + case PICOKNOW_KBID_DT_MGC4: + case PICOKNOW_KBID_DT_MGC5: + return picokdt_specializeDtKnowledgeBase(*kb, this->common, + PICOKDT_KDTTYPE_PAM); + break; + case PICOKNOW_KBID_PDF_DUR: + return picokpdf_specializePdfKnowledgeBase(*kb, this->common, + PICOKPDF_KPDFTYPE_DUR); + + break; + case PICOKNOW_KBID_PDF_LFZ: + return picokpdf_specializePdfKnowledgeBase(*kb, this->common, + PICOKPDF_KPDFTYPE_MUL); + break; + case PICOKNOW_KBID_PDF_MGC: + return picokpdf_specializePdfKnowledgeBase(*kb, this->common, + PICOKPDF_KPDFTYPE_MUL); + break; + case PICOKNOW_KBID_PDF_PHS: + return picokpdf_specializePdfKnowledgeBase(*kb, this->common, + PICOKPDF_KPDFTYPE_PHS); + break; + + + +#if defined(PICO_DEBUG) + case PICOKNOW_KBID_DBG: + return picokdbg_specializeDbgKnowledgeBase(*kb, this->common); + break; +#endif + + default: + break; + } + return PICO_OK; +} + + +static pico_status_t picorsrc_releaseKnowledgeBase( + picorsrc_ResourceManager this, + picoknow_KnowledgeBase * kb) +{ + (*kb) = NULL; + return PICO_OK; +} + +static pico_status_t picorsrc_getKbList(picorsrc_ResourceManager this, + picoos_uint8 * data, + picoos_uint32 datalen, + picoknow_KnowledgeBase * kbList) +{ + + pico_status_t status = PICO_OK; + picoos_uint32 curpos = 0, offset, size; + picoos_uint8 i, numKbs, kbid; + picoos_char str[PICOKNOW_MAX_KB_NAME_SIZ]; + picoknow_KnowledgeBase kb; + + *kbList = NULL; + datalen = datalen; + /* read number of fields */ + numKbs = data[curpos++]; + PICODBG_DEBUG(("number of kbs (unrestricted) = %i",numKbs)); + status = (numKbs <= PICOKNOW_MAX_NUM_RESOURCE_KBS) ? PICO_OK : PICO_EXC_FILE_CORRUPT; + /* read in all kb names */ + PICODBG_DEBUG(("number of kbs = %i",numKbs)); + i = 0; + while ((PICO_OK == status) && (i++ < numKbs)) { + status = (picoos_get_str((picoos_char *)data,&curpos,str,PICOOS_MAX_FIELD_STRING_LEN)) ? PICO_OK : PICO_EXC_FILE_CORRUPT; + PICODBG_DEBUG(("contains knowledge base %s (status: %i)",str, status)); + } + /* consume termination of last str */ + curpos++; + i = 0; + while ((PICO_OK == status) && (i++ < numKbs)) { + kbid = data[curpos++]; + PICODBG_DEBUG(("got kb id %i, curpos now %i",kbid, curpos)); + status = picoos_read_mem_pi_uint32(data,&curpos,&offset); + PICODBG_DEBUG(("got kb offset %i, curpos now %i",offset, curpos)); + status = picoos_read_mem_pi_uint32(data,&curpos,&size); + PICODBG_DEBUG(("got kb size %i, curpos now %i",size, curpos)); + if (PICO_OK == status) { + if (0 == offset) { + /* currently we consider a kb mentioned in resource but with offset 0 (no knowledge) as + * different form a kb not mentioned at all. We might reconsider that later. */ + PICODBG_DEBUG((" kb (id %i) is mentioned but empty (base:%i, size:%i)",kb->id, kb->base, kb->size)); + status = picorsrc_createKnowledgeBase(this, NULL, size, (picoknow_kb_id_t)kbid, &kb); + } else { + status = picorsrc_createKnowledgeBase(this, data+offset, size, (picoknow_kb_id_t)kbid, &kb); + } + PICODBG_DEBUG(("found kb (id %i) starting at %i with size %i",kb->id, kb->base, kb->size)); + if (PICO_OK == status) { + kb->next = *kbList; + *kbList = kb; + } + } + } + if (PICO_OK != status) { + kb = *kbList; + while (NULL != kb) { + picorsrc_releaseKnowledgeBase(this,&kb); + } + } + + return status; + +} + +/* load resource file. the type of resource file etc. are in the header, + * then follows the directory, then the knowledge bases themselves (as byte streams) */ + +pico_status_t picorsrc_loadResource(picorsrc_ResourceManager this, + picoos_char * fileName, picorsrc_Resource * resource) +{ + picorsrc_Resource res; + picoos_uint32 headerlen, len,maxlen; + picoos_file_header_t header; + picoos_uint8 rem; + pico_status_t status = PICO_OK; + + if (resource == NULL) { + return PICO_ERR_NULLPTR_ACCESS; + } else { + *resource = NULL; + } + + res = picorsrc_newResource(this->common->mm); + + if (NULL == res) { + return picoos_emRaiseException(this->common->em,PICO_EXC_OUT_OF_MEM,NULL,NULL); + } + + if (PICO_MAX_NUM_RESOURCES <= this->numResources) { + picoos_deallocate(this->common->mm, (void *) &res); + return picoos_emRaiseException(this->common->em,PICO_EXC_MAX_NUM_EXCEED,NULL,(picoos_char *)"no more than %i resources",PICO_MAX_NUM_RESOURCES); + } + + /* ***************** parse file name for file type and parameters */ + + if (PICO_OK != parse_resource_name(fileName)) { + picoos_deallocate(this->common->mm, (void *) &res); + return PICO_EXC_UNEXPECTED_FILE_TYPE; + } + + /* ***************** get header info */ + + /* open binary file for reading (no key, nrOfBufs, bufSize) */ + PICODBG_DEBUG(("trying to open file %s",fileName)); + if (!picoos_OpenBinary(this->common, &res->file, fileName)) { + /* open didn't succeed */ + status = PICO_EXC_CANT_OPEN_FILE; + PICODBG_ERROR(("can't open file %s",fileName)); + picoos_emRaiseException(this->common->em, PICO_EXC_CANT_OPEN_FILE, + NULL, (picoos_char *) "%s", fileName); + } + if (PICO_OK == status) { + status = readHeader(this, &header, &headerlen, res->file); + /* res->file now positioned at first pos after header */ + } + + /* ***************** check header values */ + if (PICO_OK == status && isResourceLoaded(this, header.field[PICOOS_HEADER_NAME].value)) { + /* lingware is allready loaded, do nothing */ + PICODBG_WARN((">>> lingware '%s' allready loaded",header.field[PICOOS_HEADER_NAME].value)); + picoos_emRaiseWarning(this->common->em,PICO_WARN_RESOURCE_DOUBLE_LOAD,NULL,(picoos_char *)"%s",header.field[PICOOS_HEADER_NAME].value); + status = PICO_WARN_RESOURCE_DOUBLE_LOAD; + } + + if (PICO_OK == status) { + /* get data length */ + status = picoos_read_pi_uint32(res->file, &len); + PICODBG_DEBUG(("found net resource len of %i",len)); + /* allocate memory */ + if (PICO_OK == status) { + PICODBG_TRACE((">>> 2")); + maxlen = len + PICOOS_ALIGN_SIZE; /* once would be sufficient? */ + res->raw_mem = picoos_allocProtMem(this->common->mm, maxlen); + /* res->size = maxlen; */ + status = (NULL == res->raw_mem) ? PICO_EXC_OUT_OF_MEM : PICO_OK; + } + if (PICO_OK == status) { + rem = (uintptr_t) res->raw_mem % PICOOS_ALIGN_SIZE; + if (rem > 0) { + res->start = res->raw_mem + (PICOOS_ALIGN_SIZE - rem); + } else { + res->start = res->raw_mem; + } + + /* read file contents into memory */ + status = (picoos_ReadBytes(res->file, res->start, &len)) ? PICO_OK + : PICO_ERR_OTHER; + /* resources are read-only; the following write protection + has an effect in test configurations only */ + picoos_protectMem(this->common->mm, res->start, len, /*enable*/TRUE); + } + /* note resource unique name */ + if (PICO_OK == status) { + if (picoos_strlcpy(res->name,header.field[PICOOS_HEADER_NAME].value,PICORSRC_MAX_RSRC_NAME_SIZ) < PICORSRC_MAX_RSRC_NAME_SIZ) { + PICODBG_DEBUG(("assigned name %s to resource",res->name)); + status = PICO_OK; + } else { + status = PICO_ERR_INDEX_OUT_OF_RANGE; + PICODBG_ERROR(("failed assigning name %s to resource", + res->name)); + picoos_emRaiseException(this->common->em, + PICO_ERR_INDEX_OUT_OF_RANGE, NULL, + (picoos_char *)"resource %s",res->name); + } + } + + /* get resource type */ + if (PICO_OK == status) { + if (!picoos_strcmp(header.field[PICOOS_HEADER_CONTENT_TYPE].value, PICORSRC_FIELD_VALUE_TEXTANA)) { + res->type = PICORSRC_TYPE_TEXTANA; + } else if (!picoos_strcmp(header.field[PICOOS_HEADER_CONTENT_TYPE].value, PICORSRC_FIELD_VALUE_SIGGEN)) { + res->type = PICORSRC_TYPE_SIGGEN; + } else if (!picoos_strcmp(header.field[PICOOS_HEADER_CONTENT_TYPE].value, PICORSRC_FIELD_VALUE_SIGGEN)) { + res->type = PICORSRC_TYPE_USER_LEX; + } else if (!picoos_strcmp(header.field[PICOOS_HEADER_CONTENT_TYPE].value, PICORSRC_FIELD_VALUE_SIGGEN)) { + res->type = PICORSRC_TYPE_USER_PREPROC; + } else { + res->type = PICORSRC_TYPE_OTHER; + } + } + + if (PICO_OK == status) { + /* create kb list from resource */ + status = picorsrc_getKbList(this, res->start, len, &res->kbList); + } + } + + if (status == PICO_OK) { + /* add resource to rm */ + res->next = this->resources; + this->resources = res; + this->numResources++; + *resource = res; + PICODBG_DEBUG(("done loading resource %s from %s", res->name, fileName)); + } else { + picorsrc_disposeResource(this->common->mm, &res); + PICODBG_ERROR(("failed to load resource")); + } + + if (status < 0) { + return status; + } else { + return PICO_OK; + } +} + +static pico_status_t picorsrc_releaseKbList(picorsrc_ResourceManager this, picoknow_KnowledgeBase * kbList) +{ + picoknow_KnowledgeBase kbprev, kb; + kb = *kbList; + while (NULL != kb) { + kbprev = kb; + kb = kb->next; + picoknow_disposeKnowledgeBase(this->common->mm,&kbprev); + } + *kbList = NULL; + return PICO_OK; +} + +/* unload resource file. (if resource file is busy, warn and don't unload) */ +pico_status_t picorsrc_unloadResource(picorsrc_ResourceManager this, picorsrc_Resource * resource) { + + picorsrc_Resource r1, r2, rsrc; + + if (resource == NULL) { + return PICO_ERR_NULLPTR_ACCESS; + } else { + rsrc = *resource; + } + + if (rsrc->lockCount > 0) { + return PICO_EXC_RESOURCE_BUSY; + } + /* terminate */ + if (rsrc->file != NULL) { + picoos_CloseBinary(this->common, &rsrc->file); + } + if (NULL != rsrc->raw_mem) { + picoos_deallocProtMem(this->common->mm, (void *) &rsrc->raw_mem); + PICODBG_DEBUG(("deallocated raw mem")); + } + + r1 = NULL; + r2 = this->resources; + while (r2 != NULL && r2 != rsrc) { + r1 = r2; + r2 = r2->next; + } + if (NULL == r1) { + this->resources = rsrc->next; + } else if (NULL == r2) { + /* didn't find resource in rm! */ + return PICO_ERR_OTHER; + } else { + r1->next = rsrc->next; + } + + if (NULL != rsrc->kbList) { + picorsrc_releaseKbList(this, &rsrc->kbList); + } + + picoos_deallocate(this->common->mm,(void **)resource); + this->numResources--; + + return PICO_OK; +} + + +pico_status_t picorsrc_createDefaultResource(picorsrc_ResourceManager this + /*, picorsrc_Resource * resource */) +{ + picorsrc_Resource res; + pico_status_t status = PICO_OK; + + + /* *resource = NULL; */ + + if (PICO_MAX_NUM_RESOURCES <= this->numResources) { + return picoos_emRaiseException(this->common->em,PICO_EXC_MAX_NUM_EXCEED,NULL,(picoos_char *)"no more than %i resources",PICO_MAX_NUM_RESOURCES); + } + + res = picorsrc_newResource(this->common->mm); + + if (NULL == res) { + return picoos_emRaiseException(this->common->em,PICO_EXC_OUT_OF_MEM,NULL,NULL); + } + + if (picoos_strlcpy(res->name,PICOKNOW_DEFAULT_RESOURCE_NAME,PICORSRC_MAX_RSRC_NAME_SIZ) < PICORSRC_MAX_RSRC_NAME_SIZ) { + PICODBG_DEBUG(("assigned name %s to default resource",res->name)); + status = PICO_OK; + } else { + PICODBG_ERROR(("failed assigning name %s to default resource",res->name)); + status = PICO_ERR_INDEX_OUT_OF_RANGE; + } + status = picorsrc_createKnowledgeBase(this, NULL, 0, (picoknow_kb_id_t)PICOKNOW_KBID_FIXED_IDS, &res->kbList); + + if (PICO_OK == status) { + res->next = this->resources; + this->resources = res; + this->numResources++; + /* *resource = res; */ + + } + + + return status; + +} + +pico_status_t picorsrc_rsrcGetName(picorsrc_Resource this, + picoos_char * name, picoos_uint32 maxlen) { + if (!picoctrl_isValidResourceHandle(this)) { + return PICO_ERR_INVALID_ARGUMENT; + } + picoos_strlcpy(name, this->name,maxlen); + return PICO_OK; +} + + +/* ******* accessing voice definitions **************************************/ + + +static pico_status_t findVoiceDefinition(picorsrc_ResourceManager this, + const picoos_char * voiceName, picorsrc_VoiceDefinition * vdef) +{ + picorsrc_VoiceDefinition v; + PICODBG_DEBUG(("finding voice name %s",voiceName)); + if (NULL == this) { + return PICO_ERR_NULLPTR_ACCESS; + } + v = this->vdefs; + while (NULL != v && (0 != picoos_strcmp(v->voiceName,voiceName))) { + PICODBG_DEBUG(("%s doesnt match",v->voiceName)); + v = v->next; + } + *vdef = v; + if (v == NULL) { + PICODBG_DEBUG(("didnt find voice name %s",voiceName)); + } else { + PICODBG_DEBUG(("found voice name %s",voiceName)); + } + return PICO_OK; +} + + +pico_status_t picorsrc_addResourceToVoiceDefinition(picorsrc_ResourceManager this, + picoos_char * voiceName, picoos_char * resourceName) +{ + picorsrc_VoiceDefinition vdef; + + if (NULL == this) { + PICODBG_ERROR(("this is NULL")); + return PICO_ERR_NULLPTR_ACCESS; + } + if ((PICO_OK == findVoiceDefinition(this,voiceName,&vdef)) && (NULL != vdef)) { + if (PICO_MAX_NUM_RSRC_PER_VOICE <= vdef->numResources) { + return picoos_emRaiseException(this->common->em,PICO_EXC_MAX_NUM_EXCEED,NULL,(picoos_char *)"no more than %i resources per voice",PICO_MAX_NUM_RSRC_PER_VOICE); + } + if (picoos_strlcpy(vdef->resourceName[vdef->numResources++], resourceName, + PICORSRC_MAX_RSRC_NAME_SIZ) < PICORSRC_MAX_RSRC_NAME_SIZ) { + PICODBG_DEBUG(("vdef added resource '%s' to voice '%s'",resourceName,voiceName)); + return PICO_OK; + } else { + PICODBG_ERROR(("illegal name (%s)",resourceName)); + return picoos_emRaiseException(this->common->em,PICO_EXC_NAME_ILLEGAL,NULL,(picoos_char *)"%s",resourceName); + } + + } else { + return picoos_emRaiseException(this->common->em,PICO_EXC_NAME_UNDEFINED,NULL,(picoos_char *)"%s",voiceName); + } +} + + +pico_status_t picorsrc_createVoiceDefinition(picorsrc_ResourceManager this, + picoos_char * voiceName) +{ + picorsrc_VoiceDefinition vdef; + + if (NULL == this) { + PICODBG_ERROR(("this is NULL")); + return PICO_ERR_NULLPTR_ACCESS; + } + if ((PICO_OK == findVoiceDefinition(this,voiceName,&vdef)) && (NULL != vdef)) { + PICODBG_ERROR(("voice %s allready defined",voiceName)); + return picoos_emRaiseException(this->common->em,PICO_EXC_NAME_CONFLICT,NULL,NULL); + } + if (PICO_MAX_NUM_VOICE_DEFINITIONS <= this->numVdefs) { + PICODBG_ERROR(("max number of vdefs exceeded (%i)",this->numVdefs)); + return picoos_emRaiseException(this->common->em,PICO_EXC_MAX_NUM_EXCEED,NULL,(picoos_char *)"no more than %i voice definitions",PICO_MAX_NUM_VOICE_DEFINITIONS); + } + if (NULL == this->freeVdefs) { + vdef = picorsrc_newVoiceDefinition(this->common->mm); + } else { + vdef = this->freeVdefs; + this->freeVdefs = vdef->next; + vdef->voiceName[0] = NULLC; + vdef->numResources = 0; + vdef->next = NULL; + } + if (NULL == vdef) { + return picoos_emRaiseException(this->common->em,PICO_EXC_OUT_OF_MEM,NULL,NULL); + } + if (picoos_strlcpy(vdef->voiceName, voiceName, + PICO_MAX_VOICE_NAME_SIZE) < PICO_MAX_VOICE_NAME_SIZE) { + vdef->next = this->vdefs; + this->vdefs = vdef; + this->numVdefs++; + if (PICO_OK != picorsrc_addResourceToVoiceDefinition(this,voiceName,PICOKNOW_DEFAULT_RESOURCE_NAME)) { + return picoos_emRaiseException(this->common->em,PICO_ERR_OTHER,NULL,(picoos_char *)"problem loading default resource %s",voiceName); + } + PICODBG_DEBUG(("vdef created (%s)",voiceName)); + return PICO_OK; + } else { + PICODBG_ERROR(("illegal name (%s)",voiceName)); + return picoos_emRaiseException(this->common->em,PICO_EXC_NAME_ILLEGAL,NULL,(picoos_char *)"%s",voiceName); + } +} + + +pico_status_t picorsrc_releaseVoiceDefinition(picorsrc_ResourceManager this, + picoos_char *voiceName) +{ + picorsrc_VoiceDefinition v, l; + + if (this == NULL) { + return PICO_ERR_NULLPTR_ACCESS; + } + + l = NULL; + v = this->vdefs; + while ((v != NULL) && (picoos_strcmp(v->voiceName, voiceName) != 0)) { + l = v; + v = v->next; + } + if (v != NULL) { + /* remove v from vdefs list */ + if (l != NULL) { + l->next = v->next; + } else { + this->vdefs = v->next; + } + /* insert v at head of freeVdefs list */ + v->next = this->freeVdefs; + this->freeVdefs = v; + this->numVdefs--; + return PICO_OK; + } else { + /* we should rather return a warning, here */ + /* return picoos_emRaiseException(this->common->em,PICO_EXC_NAME_UNDEFINED,"%s", NULL); */ + return PICO_OK; + } +} + + + +/* ******* accessing voices **************************************/ + + +/* create voice, given a voice name. the corresponding lock counts are incremented */ + +pico_status_t picorsrc_createVoice(picorsrc_ResourceManager this, const picoos_char * voiceName, picorsrc_Voice * voice) { + + picorsrc_VoiceDefinition vdef; + picorsrc_Resource rsrc; + picoos_uint8 i, required; + picoknow_KnowledgeBase kb; + /* pico_status_t status = PICO_OK; */ + + PICODBG_DEBUG(("creating voice %s",voiceName)); + + if (NULL == this) { + PICODBG_ERROR(("this is NULL")); + return PICO_ERR_NULLPTR_ACCESS; + + } + /* check number of voices */ + if (PICORSRC_MAX_NUM_VOICES <= this->numVoices) { + PICODBG_ERROR(("PICORSRC_MAX_NUM_VOICES exceeded")); + return picoos_emRaiseException(this->common->em,PICO_EXC_MAX_NUM_EXCEED,NULL,(picoos_char *)"no more than %i voices",PICORSRC_MAX_NUM_VOICES); + } + + /* find voice definition for that name */ + if (!(PICO_OK == findVoiceDefinition(this,voiceName,&vdef)) || (NULL == vdef)) { + PICODBG_ERROR(("no voice definition for %s",voiceName)); + return picoos_emRaiseException(this->common->em,PICO_EXC_NAME_UNDEFINED,NULL,(picoos_char *)"voice definition %s",voiceName); + + } + PICODBG_DEBUG(("found voice definition for %s",voiceName)); + + /* check that resources are loaded */ + for (i = 0; i < vdef->numResources; i++) { + required = (NULLC != vdef->resourceName[i][0]); + if (required && !isResourceLoaded(this,vdef->resourceName[i])) { + PICODBG_ERROR(("resource missing")); + return picoos_emRaiseException(this->common->em,PICO_EXC_RESOURCE_MISSING,NULL,(picoos_char *)"resource %s for voice %s",vdef->resourceName[i],voiceName); + } + } + + /* allocate new voice */ + if (NULL == this->freeVoices) { + *voice = picorsrc_newVoice(this->common->mm); + } else { + *voice = this->freeVoices; + this->freeVoices = (*voice)->next; + picorsrc_initializeVoice(*voice); + } + if (*voice == NULL) { + return picoos_emRaiseException(this->common->em, PICO_EXC_OUT_OF_MEM, NULL, NULL); + } + this->numVoices++; + + /* copy resource kb pointers into kb array of voice */ + for (i = 0; i < vdef->numResources; i++) { + required = (NULLC != vdef->resourceName[i][0]); + if (required) { + findResource(this,vdef->resourceName[i],&rsrc); + (*voice)->resourceArray[(*voice)->numResources++] = rsrc; + rsrc->lockCount++; + kb = rsrc->kbList; + while (NULL != kb) { + if (NULL != (*voice)->kbArray[kb->id]) { + picoos_emRaiseWarning(this->common->em,PICO_WARN_KB_OVERWRITE,NULL, (picoos_char *)"%i", kb->id); + PICODBG_WARN(("overwriting knowledge base of id %i", kb->id)); + + } + PICODBG_DEBUG(("setting knowledge base of id %i", kb->id)); + + (*voice)->kbArray[kb->id] = kb; + kb = kb->next; + } + } + } /* for */ + + return PICO_OK; +} + +/* dispose voice. the corresponding lock counts are decremented. */ + +pico_status_t picorsrc_releaseVoice(picorsrc_ResourceManager this, picorsrc_Voice * voice) +{ + picoos_uint16 i; + picorsrc_Voice v = *voice; + if (NULL == this || NULL == v) { + return PICO_ERR_NULLPTR_ACCESS; + } + for (i = 0; i < v->numResources; i++) { + v->resourceArray[i]->lockCount--; + } + v->next = this->freeVoices; + this->freeVoices = v; + this->numVoices--; + + return PICO_OK; +} + +#ifdef __cplusplus +} +#endif + +/* end picorsrc.c */ diff --git a/pico/lib/picorsrc.h b/pico/lib/picorsrc.h new file mode 100644 index 0000000..4dfb19e --- /dev/null +++ b/pico/lib/picorsrc.h @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picorsrc.h + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ +/** + * @addtogroup picorsrc + * + * Pico Resource Management module \n + * +*/ + +#ifndef PICORSRC_H_ +#define PICORSRC_H_ + +#include "picodefs.h" +#include "picoos.h" +#include "picoknow.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +#define PICORSRC_MAX_RSRC_NAME_SIZ PICO_MAX_RESOURCE_NAME_SIZE /* including terminating NULLC */ + +#define PICORSRC_MAX_NUM_VOICES 64 + +/* size of kb array of a voice */ +#define PICORSRC_KB_ARRAY_SIZE 64 + +typedef picoos_char picorsrc_resource_name_t[PICORSRC_MAX_RSRC_NAME_SIZ]; + +typedef enum picorsrc_resource_type { + PICORSRC_TYPE_NULL, + PICORSRC_TYPE_TEXTANA, + PICORSRC_TYPE_SIGGEN, + PICORSRC_TYPE_USER_LEX, + PICORSRC_TYPE_USER_PREPROC, + PICORSRC_TYPE_OTHER +} picorsrc_resource_type_t; + + +#define PICORSRC_FIELD_VALUE_TEXTANA (picoos_char *) "TEXTANA" +#define PICORSRC_FIELD_VALUE_SIGGEN (picoos_char *) "SIGGEN" +#define PICORSRC_FIELD_VALUE_USERLEX (picoos_char *) "USERLEX" +#define PICORSRC_FIELD_VALUE_USERTPP (picoos_char *) "USERTPP" + + + +typedef struct picorsrc_resource_manager * picorsrc_ResourceManager; +typedef struct picorsrc_voice * picorsrc_Voice; +typedef struct picorsrc_resource * picorsrc_Resource; + + +/* ************************************************************************** + * + * file name extensions + * + ****************************************************************************/ + +#define PICO_BIN_EXTENSION ".bin" +#define PICO_INPLACE_EXTENSION ".inp" + + + +/* ************************************************************************** + * + * construct/destruct resource manager + * + ****************************************************************************/ + +/* create resource manager, given a config file name (or default name, if empty) */ + +picorsrc_ResourceManager picorsrc_newResourceManager(picoos_MemoryManager mm, picoos_Common common /* , picoos_char * configFile */); + +void picorsrc_disposeResourceManager(picoos_MemoryManager mm, picorsrc_ResourceManager * this); + + +/* ************************************************************************** + * + * resources + * + ****************************************************************************/ + +/** + * Returns non-zero if 'resource' is a valid resource handle, zero otherwise. + */ +picoos_int16 picoctrl_isValidResourceHandle(picorsrc_Resource resource); + +/* load resource file. the type of resource file, magic numbers, checksum etc. are in the header, then follows the directory + * (with fixed structure per resource type), then the knowledge bases themselves (as byte streams) */ +pico_status_t picorsrc_loadResource(picorsrc_ResourceManager this, + picoos_char * fileName, picorsrc_Resource * resource); + +/* unload resource file. (warn if resource file is busy) */ +pico_status_t picorsrc_unloadResource(picorsrc_ResourceManager this, picorsrc_Resource * rsrc); + + +pico_status_t picorsrc_createDefaultResource(picorsrc_ResourceManager this /*, + picorsrc_Resource * resource */); + + +pico_status_t picorsrc_rsrcGetName(picorsrc_Resource resource, + picoos_char * name, picoos_uint32 maxlen); + +/* ************************************************************************** + * + * voice definitions + * + ****************************************************************************/ + + +pico_status_t picorsrc_createVoiceDefinition(picorsrc_ResourceManager this, + picoos_char * voiceName); + + +pico_status_t picorsrc_releaseVoiceDefinition(picorsrc_ResourceManager this, + picoos_char * voiceName); + +pico_status_t picorsrc_addResourceToVoiceDefinition(picorsrc_ResourceManager this, + picoos_char * voiceName, picoos_char * resourceName); + +/* ************************************************************************** + * + * voices + * + ****************************************************************************/ + +/** object : Voice + * shortcut : voice + * + */ + +typedef struct picorsrc_voice { + + picorsrc_Voice next; + + picoknow_KnowledgeBase kbArray[PICORSRC_KB_ARRAY_SIZE]; + + picoos_uint8 numResources; + + picorsrc_Resource resourceArray[PICO_MAX_NUM_RSRC_PER_VOICE]; + + +} picorsrc_voice_t; + + + +/* create voice, given a voice name. the corresponding lock counts are incremented */ +pico_status_t picorsrc_createVoice(picorsrc_ResourceManager this, const picoos_char * voiceName, picorsrc_Voice * voice); + +/* dispose voice. the corresponding lock counts are decremented. */ +pico_status_t picorsrc_releaseVoice(picorsrc_ResourceManager this, picorsrc_Voice * voice); + +#ifdef __cplusplus +} +#endif + + + +#endif /*PICORSRC_H_*/ diff --git a/pico/lib/picosa.c b/pico/lib/picosa.c new file mode 100644 index 0000000..8c58aa4 --- /dev/null +++ b/pico/lib/picosa.c @@ -0,0 +1,1743 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picosa.c + * + * sentence analysis - POS disambiguation + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include "picoos.h" +#include "picodbg.h" +#include "picobase.h" +#include "picokdt.h" +#include "picoklex.h" +#include "picoktab.h" +#include "picokfst.h" +#include "picotrns.h" +#include "picodata.h" +#include "picosa.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* PU saStep states */ +#define SA_STEPSTATE_COLLECT 0 +#define SA_STEPSTATE_PROCESS_POSD 10 +#define SA_STEPSTATE_PROCESS_WPHO 11 +#define SA_STEPSTATE_PROCESS_TRNS_PARSE 12 +#define SA_STEPSTATE_PROCESS_TRNS_FST 13 +#define SA_STEPSTATE_FEED 2 + +#define SA_MAX_ALTDESC_SIZE (30*(PICOTRNS_MAX_NUM_POSSYM + 2)) + +#define SA_MSGSTR_SIZE 32 + +/* subobject : SentAnaUnit + * shortcut : sa + * context size : one phrase, max. 30 non-PUNC items, for non-processed items + * one item if internal input empty + */ + +/** @addtogroup picosa + + internal buffers: + + - headx: array for extended item heads of fixed size (head plus + index for content, plus two fields for boundary strength/type) + + - cbuf1, cbuf2: buffers for item contents (referenced by index in + headx). Future: replace these two buffers by a single double-sided + buffer (double shrink-grow type) + + 0. bottom up filling of items in headx and cbuf1 + + 1. POS disambiguation (right-to-left, top-to-bottom): + - number and sequence of items unchanged + - item content can only get smaller (reducing nr of results in WORDINDEX) + -> info stays in "headx, cbuf1" and changed in place \n + WORDGRAPH(POSes,NA)graph -> WORDGRAPH(POS,NA)graph \n + WORDINDEX(POSes,NA)POS1ind1...POSNindN -> WORDINDEX(POS,NA)POS|ind \n + + 2. lex-index lookup and G2P (both directions possible, left-to-right done): + - number and sequence of items unchanged, item head info and content + changes + -> headx changed in place; cbuf1 to cbuf2 \n + WORDGRAPH(POS,NA)graph -> WORDPHON(POS,NA)phon \n + WORDINDEX(POS,NA)POS|ind -> WORDPHON(POS,NA)phon \n + + 3. phrasing (right-to-left): + + Previous (before introducing SBEG)\n + ---------------------------------- + 1| 2| 3| 4| \n + e.g. from WP WP WP WP WP PUNC WP WP PUNC WP WP WP PUNC FLUSH \n + e.g. to BINIT WP WP WP BPHR3 WP WP BPHR1 WP WP BSEND WP WP WP BSEND BTERM \n + |1 |2 |3 |4 \n + + 3-level bound state: to keep track of bound strength from end of + previous punc-phrase, then BOUND item output as first item + (strength from prev punc-phrase and type from current + punc-phrase). + + trailing PUNC item bound states + INIT SEND PHR1 + PUNC(SENTEND, T) B(I,T)>SEND B(S,T)>SEND B(P1,T)>SEND + PUNC(SENTEND, Q) B(I,Q)>SEND B(S,Q)>SEND B(P1,Q)>SEND + PUNC(SENTEND, E) B(I,E)>SEND B(S,E)>SEND B(P1,E)>SEND + PUNC(PHRASEEND, P) B(I,P)>PHR1 B(S,P)>PHR1 B(P1,P)>PHR1 + PUNC(PHRASEEND, FORC) B(I,P)>PHR1 B(S,P)>PHR1 B(P1,P)>PHR1 + PUNC(FLUSH, T) B(I,T).. B(S,T).. B(P1,T).. + B(T,NA) B(T,NA) B(T,NA) + >INIT >INIT >INIT + + PHR2/3 case: + trailing PUNC item bound states + INIT SEND PHR1 + PUNC(SENTEND, T) B(I,P)B(P,T)>SEND B(S,P)B(P,T)>SEND B(P1,P)B(P,T)>SEND + PUNC(SENTEND, Q) B(I,P)B(P,Q)>SEND B(S,P)B(P,Q)>SEND B(P1,P)B(P,Q)>SEND + PUNC(SENTEND, E) B(I,P)B(P,E)>SEND B(S,P)B(P,E)>SEND B(P1,P)B(P,E)>SEND + PUNC(PHRASEEND, P) B(I,P)B(P,P)>PHR1 B(S,P)B(P,P)>PHR1 B(P1,P)B(P,P)>PHR1 + PUNC(PHREND, FORC) B(I,P)B(P,P)>PHR1 B(S,P)B(P,P)>PHR1 B(P1,P)B(P,P)>PHR1 + PUNC(FLUSH, T) B(I,P)B(P,T).. B(S,T)B(P,T).. B(P1,T)B(P,T).. + B(T,NA) B(T,NA) B(T,NA) + >INIT >INIT >INIT + + Current + -------- + e.g. from WP WP WP WP WP PUNC WP WP PUNC WP WP WP PUNC FLUSH + e.g. to BSBEG WP WP WP BPHR3 WP WP BPHR1 WP WP BSEND BSBEG WP WP WP BSEND BTERM + |1 |2 |3 |4 + + 2-level bound state: The internal buffer contains one primary phrase (sometimes forced, if buffer + allmost full), with the trailing PUNCT item included (last item). + If the trailing PUNC is a a primary phrase separator, the + item is not output, but instead, the bound state is set to PPHR, so that the correct BOUND can + be output at the start of the next primary phrase. + Otherwise, + the item is converted to the corresponding BOUND and output. the bound state is set to SSEP, + so that a BOUND of type SBEG is output at the start of the next primary phrase. + + trailing PUNC item bound states + SSEP PPHR + PUNC(SENTEND, X) B(B,X)>SSEP B(P1,X)>SSEP (X = T | Q | E) + PUNC(FLUSH, T) B(B,T)>SSEP* B(P1,T)>SSEP + PUNC(PHRASEEND, P) B(B,P)>PPHR B(P1,P)>PPHR + PUNC(PHRASEEND, FORC) B(B,P)>PPHR B(P1,P)>PPHR + +* If more than one sentence separators follow each other (e.g. SEND-FLUSH, SEND-SEND) then + all but the first will be treated as an (empty) phrase containing just this item. + If this (single) item is a flush, creation of SBEG is suppressed. + + + - dtphr phrasing tree (rather subphrasing tree it should be called) + determines + BOUND_PHR2 + BOUND_PHR3 + - boundary strenghts are determined for every word (except the + first one) from right-to-left. The boundary types mark the phrase + type of the phrase following the boundary. + - number of items actually changed (new BOUND items added): because + of fixed size without content, two fields are contained in headx + to indicate if a BOUND needs to be added to the LEFT of the item. + -> headx further extended with boundary strength and type info to + indicate that to the left of the headx ele a BOUND needs to be + inserted when outputting. + + 4. accentuation: + - number of items unchanged, content unchanged, only head info changes + -> changed in place in headx +*/ + + +typedef struct { + picodata_itemhead_t head; + picoos_uint16 cind; +} picosa_headx_t; + + +typedef struct sa_subobj { + picoos_uint8 procState; /* for next processing step decision */ + + picoos_uint8 inspaceok; /* flag: headx/cbuf1 has space for an item */ + picoos_uint8 needsmoreitems; /* flag: need more items */ + picoos_uint8 phonesTransduced; /* flag: */ + + picoos_uint8 tmpbuf[PICODATA_MAX_ITEMSIZE]; /* tmp. location for an item */ + + picosa_headx_t headx[PICOSA_MAXNR_HEADX]; + picoos_uint16 headxBottom; /* bottom */ + picoos_uint16 headxLen; /* length, 0 if empty */ + + picoos_uint8 cbuf1[PICOSA_MAXSIZE_CBUF]; + picoos_uint16 cbuf1BufSize; /* actually allocated size */ + picoos_uint16 cbuf1Len; /* length, 0 if empty */ + + picoos_uint8 cbuf2[PICOSA_MAXSIZE_CBUF]; + picoos_uint16 cbuf2BufSize; /* actually allocated size */ + picoos_uint16 cbuf2Len; /* length, 0 if empty */ + + picotrns_possym_t phonBufA[PICOTRNS_MAX_NUM_POSSYM+1]; + picotrns_possym_t phonBufB[PICOTRNS_MAX_NUM_POSSYM+1]; + picotrns_possym_t * phonBuf; + picotrns_possym_t * phonBufOut; + picoos_uint16 phonReadPos, phonWritePos; /* next pos to read from phonBufIn, next pos to write to phonBufIn */ + picoos_uint16 nextReadPos; /* position of (potential) next item to read from */ + + + /* buffer for internal calculation of transducer */ + picotrns_AltDesc altDescBuf; + /* the number of AltDesc in the buffer */ + picoos_uint16 maxAltDescLen; + + /* tab knowledge base */ + picoktab_Graphs tabgraphs; + picoktab_Phones tabphones; + picoktab_Pos tabpos; + picoktab_FixedIds fixedIds; + + /* dtposd knowledge base */ + picokdt_DtPosD dtposd; + + /* dtg2p knowledge base */ + picokdt_DtG2P dtg2p; + + /* lex knowledge base */ + picoklex_Lex lex; + + /* ulex knowledge bases */ + picoos_uint8 numUlex; + picoklex_Lex ulex[PICOKNOW_MAX_NUM_ULEX]; + + /* fst knowledge bases */ + picoos_uint8 numFsts; + picokfst_FST fst[PICOKNOW_MAX_NUM_WPHO_FSTS]; + picoos_uint8 curFst; /* the fst to be applied next */ + + +} sa_subobj_t; + + +static pico_status_t saInitialize(register picodata_ProcessingUnit this, picoos_int32 resetMode) { + sa_subobj_t * sa; + picoos_uint16 i; + picokfst_FST fst; + picoknow_kb_id_t fstKbIds[PICOKNOW_MAX_NUM_WPHO_FSTS] = PICOKNOW_KBID_WPHO_ARRAY; + picoklex_Lex ulex; + picoknow_kb_id_t ulexKbIds[PICOKNOW_MAX_NUM_ULEX] = PICOKNOW_KBID_ULEX_ARRAY; + + PICODBG_DEBUG(("calling")); + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(this->common->em, + PICO_ERR_NULLPTR_ACCESS, NULL, NULL); + } + sa = (sa_subobj_t *) this->subObj; + + /* sa->common = this->common; */ + + sa->procState = SA_STEPSTATE_COLLECT; + + sa->inspaceok = TRUE; + sa->needsmoreitems = TRUE; + + sa->headxBottom = 0; + sa->headxLen = 0; + sa->cbuf1BufSize = PICOSA_MAXSIZE_CBUF; + sa->cbuf2BufSize = PICOSA_MAXSIZE_CBUF; + sa->cbuf1Len = 0; + sa->cbuf2Len = 0; + + /* init headx, cbuf1, cbuf2 */ + for (i = 0; i < PICOSA_MAXNR_HEADX; i++){ + sa->headx[i].head.type = 0; + sa->headx[i].head.info1 = PICODATA_ITEMINFO1_NA; + sa->headx[i].head.info2 = PICODATA_ITEMINFO2_NA; + sa->headx[i].head.len = 0; + sa->headx[i].cind = 0; + } + for (i = 0; i < PICOSA_MAXSIZE_CBUF; i++) { + sa->cbuf1[i] = 0; + sa->cbuf2[i] = 0; + } + + + /* possym buffer */ + sa->phonesTransduced = FALSE; + sa->phonBuf = sa->phonBufA; + sa->phonBufOut = sa->phonBufB; + sa->phonReadPos = 0; + sa->phonWritePos = 0; + sa->nextReadPos = 0; + + if (resetMode == PICO_RESET_SOFT) { + /*following initializations needed only at startup or after a full reset*/ + return PICO_OK; + } + + /* kb fst[] */ + sa->numFsts = 0; + for (i = 0; ivoice->kbArray[fstKbIds[i]]); + if (NULL != fst) { + sa->fst[sa->numFsts++] = fst; + } + } + sa->curFst = 0; + PICODBG_DEBUG(("got %i fsts", sa->numFsts)); + /* kb fixedIds */ + sa->fixedIds = picoktab_getFixedIds(this->voice->kbArray[PICOKNOW_KBID_FIXED_IDS]); + + /* kb tabgraphs */ + sa->tabgraphs = + picoktab_getGraphs(this->voice->kbArray[PICOKNOW_KBID_TAB_GRAPHS]); + if (sa->tabgraphs == NULL) { + return picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + PICODBG_DEBUG(("got tabgraphs")); + + /* kb tabphones */ + sa->tabphones = + picoktab_getPhones(this->voice->kbArray[PICOKNOW_KBID_TAB_PHONES]); + if (sa->tabphones == NULL) { + return picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + PICODBG_DEBUG(("got tabphones")); + +#ifdef PICO_DEBU + { + picoos_uint16 itmp; + for (itmp = 0; itmp < 256; itmp++) { + if (picoktab_hasVowelProp(sa->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones hasVowel: %d", itmp)); + } + if (picoktab_hasDiphthProp(sa->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones hasDiphth: %d", itmp)); + } + if (picoktab_hasGlottProp(sa->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones hasGlott: %d", itmp)); + } + if (picoktab_hasNonsyllvowelProp(sa->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones hasNonsyllvowel: %d", itmp)); + } + if (picoktab_hasSyllconsProp(sa->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones hasSyllcons: %d", itmp)); + } + if (picoktab_isPrimstress(sa->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones isPrimstress: %d", itmp)); + } + if (picoktab_isSecstress(sa->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones isSecstress: %d", itmp)); + } + if (picoktab_isSyllbound(sa->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones isSyllbound: %d", itmp)); + } + if (picoktab_isPause(sa->tabphones, itmp)) { + PICODBG_DEBUG(("tabphones isPause: %d", itmp)); + } + } + + PICODBG_DEBUG(("tabphones primstressID: %d", + picoktab_getPrimstressID(sa->tabphones))); + PICODBG_DEBUG(("tabphones secstressID: %d", + picoktab_getSecstressID(sa->tabphones))); + PICODBG_DEBUG(("tabphones syllboundID: %d", + picoktab_getSyllboundID(sa->tabphones))); + PICODBG_DEBUG(("tabphones pauseID: %d", + picoktab_getPauseID(sa->tabphones))); + } +#endif + + /* kb tabpos */ + sa->tabpos = + picoktab_getPos(this->voice->kbArray[PICOKNOW_KBID_TAB_POS]); + if (sa->tabpos == NULL) { + return picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + PICODBG_DEBUG(("got tabpos")); + + /* kb dtposd */ + sa->dtposd = picokdt_getDtPosD(this->voice->kbArray[PICOKNOW_KBID_DT_POSD]); + if (sa->dtposd == NULL) { + return picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + PICODBG_DEBUG(("got dtposd")); + + /* kb dtg2p */ + sa->dtg2p = picokdt_getDtG2P(this->voice->kbArray[PICOKNOW_KBID_DT_G2P]); + if (sa->dtg2p == NULL) { + return picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + PICODBG_DEBUG(("got dtg2p")); + + /* kb lex */ + sa->lex = picoklex_getLex(this->voice->kbArray[PICOKNOW_KBID_LEX_MAIN]); + if (sa->lex == NULL) { + return picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + PICODBG_DEBUG(("got lex")); + + /* kb ulex[] */ + sa->numUlex = 0; + for (i = 0; ivoice->kbArray[ulexKbIds[i]]); + if (NULL != ulex) { + sa->ulex[sa->numUlex++] = ulex; + } + } + PICODBG_DEBUG(("got %i user lexica", sa->numUlex)); + + return PICO_OK; +} + +static picodata_step_result_t saStep(register picodata_ProcessingUnit this, + picoos_int16 mode, + picoos_uint16 *numBytesOutput); + +static pico_status_t saTerminate(register picodata_ProcessingUnit this) { + return PICO_OK; +} + +static pico_status_t saSubObjDeallocate(register picodata_ProcessingUnit this, + picoos_MemoryManager mm) { + sa_subobj_t * sa; + if (NULL != this) { + sa = (sa_subobj_t *) this->subObj; + picotrns_deallocate_alt_desc_buf(mm,&sa->altDescBuf); + picoos_deallocate(mm, (void *) &this->subObj); + } + return PICO_OK; +} + + +picodata_ProcessingUnit picosa_newSentAnaUnit(picoos_MemoryManager mm, + picoos_Common common, + picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, + picorsrc_Voice voice) { + picodata_ProcessingUnit this; + sa_subobj_t * sa; + this = picodata_newProcessingUnit(mm, common, cbIn, cbOut, voice); + if (this == NULL) { + return NULL; + } + + this->initialize = saInitialize; + PICODBG_DEBUG(("set this->step to saStep")); + this->step = saStep; + this->terminate = saTerminate; + this->subDeallocate = saSubObjDeallocate; + + this->subObj = picoos_allocate(mm, sizeof(sa_subobj_t)); + if (this->subObj == NULL) { + picoos_deallocate(mm, (void *)&this); + picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, NULL, NULL); + return NULL; + } + + sa = (sa_subobj_t *) this->subObj; + + sa->altDescBuf = picotrns_allocate_alt_desc_buf(mm, SA_MAX_ALTDESC_SIZE, &sa->maxAltDescLen); + if (NULL == sa->altDescBuf) { + picotrns_deallocate_alt_desc_buf(mm,&sa->altDescBuf); + picoos_deallocate(mm, (void *)&sa); + picoos_deallocate(mm, (void *)&this); + picoos_emRaiseException(common->em,PICO_EXC_OUT_OF_MEM, NULL, NULL); + } + + + saInitialize(this, PICO_RESET_FULL); + return this; +} + + +/* ***********************************************************************/ +/* PROCESS_POSD disambiguation functions */ +/* ***********************************************************************/ + +/* find next POS to the right of 'ind' and return its POS and index */ +static picoos_uint8 saPosDItemSeqGetPosRight(register picodata_ProcessingUnit this, + register sa_subobj_t *sa, + const picoos_uint16 ind, + const picoos_uint16 top, + picoos_uint16 *rightind) { + picoos_uint8 val; + picoos_int32 i; + + val = PICOKDT_EPSILON; + for (i = ind + 1; ((val == PICOKDT_EPSILON) && (i < top)); i++) { + if ((sa->headx[i].head.type == PICODATA_ITEM_WORDGRAPH) || + (sa->headx[i].head.type == PICODATA_ITEM_WORDINDEX) || + (sa->headx[i].head.type == PICODATA_ITEM_WORDPHON) ) { + val = sa->headx[i].head.info1; + } + } + *rightind = i - 1; + return val; +} + + +/* left-to-right, for each WORDGRAPH/WORDINDEX/WORDPHON do posd */ +static pico_status_t saDisambPos(register picodata_ProcessingUnit this, + register sa_subobj_t *sa) { + picokdt_classify_result_t dtres; + picoos_uint8 half_nratt_posd = PICOKDT_NRATT_POSD >> 1; + picoos_uint16 valbuf[PICOKDT_NRATT_POSD]; /* only [0..half_nratt_posd] can be >2^8 */ + picoos_uint16 prevout; /* direct dt output (hist.) or POS of prev word */ + picoos_uint16 lastprev3; /* last index of POS(es) found to the left */ + picoos_uint16 curPOS; /* POS(es) of current word */ + picoos_int32 first; /* index of first item with POS(es) */ + picoos_int32 ci; + picoos_uint8 okay; /* two uses: processing okay and lexind resovled */ + picoos_uint8 i; + picoos_uint16 inval; + picoos_uint16 fallback; + + /* set initial values */ + okay = TRUE; + prevout = PICOKDT_HISTORY_ZERO; + curPOS = PICODATA_ITEMINFO1_ERR; + first = 0; + + while ((first < sa->headxLen) && + (sa->headx[first].head.type != PICODATA_ITEM_WORDGRAPH) && + (sa->headx[first].head.type != PICODATA_ITEM_WORDINDEX) && + (sa->headx[first].head.type != PICODATA_ITEM_WORDPHON)) { + first++; + } + if (first >= sa->headxLen) { + /* phrase not containing an item with POSes info, e.g. single flush */ + PICODBG_DEBUG(("no item with POSes found")); + return PICO_OK; + } + + lastprev3 = first; + + for (i = 0; i <= half_nratt_posd; i++) { + valbuf[i] = PICOKDT_HISTORY_ZERO; + } + /* set POS(es) of current word, will be shifted afterwards */ + valbuf[half_nratt_posd+1] = sa->headx[first].head.info1; + for (i = half_nratt_posd+2; i < PICOKDT_NRATT_POSD; i++) { + /* find next POS to the right and set valbuf[i] */ + valbuf[i] = saPosDItemSeqGetPosRight(this, sa, lastprev3, sa->headxLen, &lastprev3); + } + + PICODBG_TRACE(("headxLen: %d", sa->headxLen)); + + /* process from left to right all items in headx */ + for (ci = first; ci < sa->headxLen; ci++) { + okay = TRUE; + + PICODBG_TRACE(("iter: %d, type: %c", ci, sa->headx[ci].head.type)); + + /* if not (WORDGRAPH or WORDINDEX) */ + if ((sa->headx[ci].head.type != PICODATA_ITEM_WORDGRAPH) && + (sa->headx[ci].head.type != PICODATA_ITEM_WORDINDEX) && + (sa->headx[ci].head.type != PICODATA_ITEM_WORDPHON)) { + continue; + } + + PICODBG_TRACE(("iter: %d, curPOS: %d", ci, sa->headx[ci].head.info1)); + + /* no continue so far => at [ci] we have a WORDGRAPH / WORDINDEX item */ + /* shift all elements one position to the left */ + /* shift predicted values (history) */ + for (i=1; iheadxLen, &lastprev3); + + /* just to be on the safe side; the following should never happen */ + if (sa->headx[ci].head.info1 != valbuf[half_nratt_posd]) { + PICODBG_WARN(("syncing POS")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_INVECTOR, + NULL, NULL); + valbuf[half_nratt_posd] = sa->headx[ci].head.info1; + } + + curPOS = valbuf[half_nratt_posd]; + + /* Check if POS disambiguation not needed */ + if (picoktab_isUniquePos(sa->tabpos, (picoos_uint8) curPOS)) { + /* not needed */ + inval = 0; + fallback = 0; + if (!picokdt_dtPosDreverseMapOutFixed(sa->dtposd, curPOS, + &prevout, &fallback)) { + if (fallback) { + prevout = fallback; + + } else { + PICODBG_ERROR(("problem doing reverse output mapping")); + prevout = curPOS; + } + } + PICODBG_DEBUG(("keeping: %d", sa->headx[ci].head.info1)); + continue; + } + + /* assuming PICOKDT_NRATT_POSD == 7 */ + PICODBG_DEBUG(("%d: [%d %d %d %d %d %d %d]", + ci, valbuf[0], valbuf[1], valbuf[2], + valbuf[3], valbuf[4], valbuf[5], valbuf[6])); + + /* no continue so far => POS disambiguation needed */ + /* construct input vector, which is set in dtposd */ + if (!picokdt_dtPosDconstructInVec(sa->dtposd, valbuf)) { + /* error constructing invec */ + PICODBG_WARN(("problem with invec")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_INVECTOR, + NULL, NULL); + okay = FALSE; + } + /* classify */ + if (okay && (!picokdt_dtPosDclassify(sa->dtposd, &prevout))) { + /* error doing classification */ + PICODBG_WARN(("problem classifying")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_CLASSIFICATION, + NULL, NULL); + okay = FALSE; + } + /* decompose */ + if (okay && (!picokdt_dtPosDdecomposeOutClass(sa->dtposd, &dtres))) { + /* error decomposing */ + PICODBG_WARN(("problem decomposing")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_OUTVECTOR, + NULL, NULL); + okay = FALSE; + } + if (okay && dtres.set) { + PICODBG_DEBUG(("in: %d, out: %d", valbuf[3], dtres.class)); + } else { + PICODBG_WARN(("problem disambiguating POS")); + dtres.class = PICODATA_ITEMINFO1_ERR; + } + + if (dtres.class > 255) { + PICODBG_WARN(("dt result outside valid range, setting pos to ERR")); + dtres.class = PICODATA_ITEMINFO1_ERR; + } + + sa->headx[ci].head.info1 = (picoos_uint8)dtres.class; + if (sa->headx[ci].head.type == PICODATA_ITEM_WORDINDEX) { + /* find pos/ind entry in cbuf matching unique, + disambiguated POS, adapt current headx cind/len + accordingly */ + PICODBG_DEBUG(("select phon based on POS disambiguation")); + okay = FALSE; + for (i = 0; i < sa->headx[ci].head.len; i += PICOKLEX_POSIND_SIZE) { + PICODBG_DEBUG(("comparing POS at cind + %d", i)); + if (picoktab_isPartOfPosGroup(sa->tabpos, + (picoos_uint8)dtres.class, + sa->cbuf1[sa->headx[ci].cind + i])) { + PICODBG_DEBUG(("found match for entry %d", + i/PICOKLEX_POSIND_SIZE + 1)); + sa->headx[ci].cind += i; + okay = TRUE; + break; + } + } + /* not finding a match is possible if posd predicts a POS that + is not part of any of the input POSes -> no warning */ +#if defined(PICO_DEBUG) + if (!okay) { + PICODBG_DEBUG(("no match found, selecting 1st entry")); + } +#endif + sa->headx[ci].head.len = PICOKLEX_POSIND_SIZE; + } + } + return PICO_OK; +} + + +/* ***********************************************************************/ +/* PROCESS_WPHO functions, copy, lexindex, and g2p */ +/* ***********************************************************************/ + +/* ************** copy ***************/ + +static pico_status_t saCopyItemContent1to2(register picodata_ProcessingUnit this, + register sa_subobj_t *sa, + picoos_uint16 ind) { + picoos_uint16 i; + picoos_uint16 cind1; + + /* set headx.cind, and copy content, head unchanged */ + cind1 = sa->headx[ind].cind; + sa->headx[ind].cind = sa->cbuf2Len; + + /* check cbufLen */ + if (sa->headx[ind].head.len > (sa->cbuf2BufSize - sa->cbuf2Len)) { + sa->headx[ind].head.len = sa->cbuf2BufSize - sa->cbuf2Len; + PICODBG_WARN(("phones skipped")); + picoos_emRaiseWarning(this->common->em, + PICO_WARN_INCOMPLETE, NULL, NULL); + if (sa->headx[ind].head.len == 0) { + sa->headx[ind].cind = 0; + } + } + + for (i = 0; i < sa->headx[ind].head.len; i++) { + sa->cbuf2[sa->cbuf2Len] = sa->cbuf1[cind1 + i]; + sa->cbuf2Len++; + } + + PICODBG_DEBUG(("%c item, len: %d", + sa->headx[ind].head.type, sa->headx[ind].head.len)); + + return PICO_OK; +} + + +/* ************** lexindex ***************/ + +static pico_status_t saLexIndLookup(register picodata_ProcessingUnit this, + register sa_subobj_t *sa, + picoklex_Lex lex, + picoos_uint16 ind) { + picoos_uint8 pos; + picoos_uint8 *phones; + picoos_uint8 plen; + picoos_uint16 i; + + if (picoklex_lexIndLookup(lex, &(sa->cbuf1[sa->headx[ind].cind + 1]), + PICOKLEX_IND_SIZE, &pos, &phones, &plen)) { + sa->headx[ind].cind = sa->cbuf2Len; + + /* check cbufLen */ + if (plen > (sa->cbuf2BufSize - sa->cbuf2Len)) { + plen = sa->cbuf2BufSize - sa->cbuf2Len; + PICODBG_WARN(("phones skipped")); + picoos_emRaiseWarning(this->common->em, + PICO_WARN_INCOMPLETE, NULL, NULL); + if (plen == 0) { + sa->headx[ind].cind = 0; + } + } + + /* set item head, info1, info2 unchanged */ + sa->headx[ind].head.type = PICODATA_ITEM_WORDPHON; + sa->headx[ind].head.len = plen; + + for (i = 0; i < plen; i++) { + sa->cbuf2[sa->cbuf2Len] = phones[i]; + sa->cbuf2Len++; + } + + PICODBG_DEBUG(("%c item, pos: %d, plen: %d", + PICODATA_ITEM_WORDPHON, pos, plen)); + + } else { + PICODBG_WARN(("lexIndLookup problem")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_PU_IRREG_ITEM, + NULL, NULL); + } + return PICO_OK; +} + + + +/* ************** g2p ***************/ + + +/* Name : saGetNvowel + Function: returns vowel info in a word or word seq + Input : sInChar the grapheme string to be converted in phoneme + inLen number of bytes in grapheme buffer + inPos start position of current grapheme (0..inLen-1) + Output : nVow number of vowels in the word + nVord vowel order in the word + Returns : TRUE: processing successful; FALSE: errors +*/ +static picoos_uint8 saGetNrVowel(register picodata_ProcessingUnit this, + register sa_subobj_t *sa, + const picoos_uint8 *sInChar, + const picoos_uint16 inLen, + const picoos_uint8 inPos, + picoos_uint8 *nVow, + picoos_uint8 *nVord) { + picoos_uint32 nCount; + picoos_uint32 pos; + picoos_uint8 cstr[PICOBASE_UTF8_MAXLEN + 1]; + + /*defaults*/ + *nVow = 0; + *nVord = 0; + /*1:check wether the current char is a vowel*/ + pos = inPos; + if (!picobase_get_next_utf8char(sInChar, inLen, &pos, cstr) || + !picoktab_hasVowellikeProp(sa->tabgraphs, cstr, PICOBASE_UTF8_MAXLEN)) { + return FALSE; + } + /*2:count number of vowels in current word and find vowel order*/ + for (nCount = 0; nCount < inLen; ) { + if (!picobase_get_next_utf8char(sInChar, inLen, &nCount, cstr)) { + return FALSE; + } + if (picoktab_hasVowellikeProp(sa->tabgraphs, cstr, + PICOBASE_UTF8_MAXLEN)) { + (*nVow)++; + if (nCount == pos) { + (*nVord) = (*nVow); + } + } + } + return TRUE; +} + + +/* do g2p for a full word, right-to-left */ +static picoos_uint8 saDoG2P(register picodata_ProcessingUnit this, + register sa_subobj_t *sa, + const picoos_uint8 *graph, + const picoos_uint8 graphlen, + const picoos_uint8 pos, + picoos_uint8 *phones, + const picoos_uint16 phonesmaxlen, + picoos_uint16 *plen) { + picoos_uint16 outNp1Ch; /*last 3 outputs produced*/ + picoos_uint16 outNp2Ch; + picoos_uint16 outNp3Ch; + picoos_uint8 nPrimary; + picoos_uint8 nCount; + picoos_uint32 utfpos; + picoos_uint16 nOutVal; + picoos_uint8 okay; + picoos_uint16 phonesind; + picoos_uint8 nrvow; + picoos_uint8 ordvow; + picokdt_classify_vecresult_t dtresv; + picoos_uint16 i; + + *plen = 0; + okay = TRUE; + + /* use sa->tmpbuf[PICOSA_MAXITEMSIZE] to temporarly store the + phones which are predicted in reverse order. Once all are + available put them in phones in usuable order. phonesind is + used to fille item in reverse order starting at the end of + tmpbuf. */ + phonesind = PICOSA_MAXITEMSIZE - 1; + + /* prepare the data for loop operations */ + outNp1Ch = PICOKDT_HISTORY_ZERO; + outNp2Ch = PICOKDT_HISTORY_ZERO; + outNp3Ch = PICOKDT_HISTORY_ZERO; + + /* inner loop */ + nPrimary = 0; + + /* ************************************************/ + /* go backward grapheme by grapheme, it's utf8... */ + /* ************************************************/ + + /* set start nCount to position of start of last utfchar */ + /* ! watch out! somethimes starting at 1, sometimes at 0, + ! sometimes counting per byte, sometimes per UTF8 char */ + /* nCount is (start position + 1) of utf8 char */ + utfpos = graphlen; + if (picobase_get_prev_utf8charpos(graph, 0, &utfpos)) { + nCount = utfpos + 1; + } else { + /* should not occurr */ + PICODBG_ERROR(("invalid utf8 string, graphlen: %d", graphlen)); + return FALSE; + } + + while (nCount > 0) { + PICODBG_TRACE(("right-to-left g2p, count: %d", nCount)); + okay = TRUE; + + if (!saGetNrVowel(this, sa, graph, graphlen, nCount-1, &nrvow, + &ordvow)) { + nrvow = 0; + ordvow = 0; + } + + /* prepare input vector, set inside tree object invec, + * g2pBuildVector will call the constructInVec tree method */ + if (!picokdt_dtG2PconstructInVec(sa->dtg2p, + graph, /*grapheme start*/ + graphlen, /*grapheme length*/ + nCount-1, /*grapheme current position*/ + pos, /*Word POS*/ + nrvow, /*nr vowels if vowel, 0 else */ + ordvow, /*ord of vowel if vowel, 0 el*/ + &nPrimary, /*primary stress flag*/ + outNp1Ch, /*Right phoneme context +1*/ + outNp2Ch, /*Right phoneme context +2*/ + outNp3Ch)) { /*Right phon context +3*/ + /*Errors in preparing the input vector : skip processing*/ + PICODBG_WARN(("problem with invec")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_INVECTOR, + NULL, NULL); + okay = FALSE; + } + + /* classify using the invec in the tree object and save the direct + tree output also in the tree object */ + if (okay && (!picokdt_dtG2Pclassify(sa->dtg2p, &nOutVal))) { + /* error doing classification */ + PICODBG_WARN(("problem classifying")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_CLASSIFICATION, + NULL, NULL); + okay = FALSE; + } + + /* decompose the invec in the tree object and return result in dtresv */ + if (okay && (!picokdt_dtG2PdecomposeOutClass(sa->dtg2p, &dtresv))) { + /* error decomposing */ + PICODBG_WARN(("problem decomposing")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_OUTVECTOR, + NULL, NULL); + okay = FALSE; + } + + if (okay) { + if ((dtresv.nr == 0) || (dtresv.classvec[0] == PICOKDT_EPSILON)) { + /* no phones to be added */ + PICODBG_TRACE(("epsilon, no phone added %c", graph[nCount-1])); + ; + } else { + /* add decomposed output to tmpbuf, reverse order */ + for (i = dtresv.nr; ((((PICOSA_MAXITEMSIZE - 1) - + phonesind) 0)); ) { + i--; + PICODBG_TRACE(("%c %d",graph[nCount-1],dtresv.classvec[i])); + if (dtresv.classvec[i] > 255) { + PICODBG_WARN(("dt result outside valid range, " + "skipping phone")); + continue; + } + sa->tmpbuf[phonesind--] = (picoos_uint8)dtresv.classvec[i]; + if (!nPrimary) { + if (picoktab_isPrimstress(sa->tabphones, + (picoos_uint8)dtresv.classvec[i])) { + nPrimary = 1; + } + } + (*plen)++; + } + if (i > 0) { + PICODBG_WARN(("phones skipped")); + picoos_emRaiseWarning(this->common->em, + PICO_WARN_INCOMPLETE, NULL, NULL); + } + } + } + + /*shift tree output history and update*/ + outNp3Ch = outNp2Ch; + outNp2Ch = outNp1Ch; + outNp1Ch = nOutVal; + + /* go backward one utf8 char */ + /* nCount is in +1 domain */ + if (nCount <= 1) { + /* end of str */ + nCount = 0; + } else { + utfpos = nCount - 1; + if (!picobase_get_prev_utf8charpos(graph, 0, &utfpos)) { + /* should not occur */ + PICODBG_ERROR(("invalid utf8 string, utfpos: %d", utfpos)); + return FALSE; + } else { + nCount = utfpos + 1; + } + } + } + + /* a must be: (PICOSA_MAXITEMSIZE-1) - phonesind == *plen */ + /* now that we have all phone IDs, copy in correct order to phones */ + /* phonesind point to next free slot in the reverse domainn, + ie. inc first */ + phonesind++; + for (i = 0; i < *plen; i++, phonesind++) { + phones[i] = sa->tmpbuf[phonesind]; + } + return TRUE; +} + + +/* item in headx[ind]/cbuf1, out: modified headx and cbuf2 */ + +static pico_status_t saGraphemeToPhoneme(register picodata_ProcessingUnit this, + register sa_subobj_t *sa, + picoos_uint16 ind) { + picoos_uint16 plen; + + PICODBG_TRACE(("starting g2p")); + + if (saDoG2P(this, sa, &(sa->cbuf1[sa->headx[ind].cind]), + sa->headx[ind].head.len, sa->headx[ind].head.info1, + &(sa->cbuf2[sa->cbuf2Len]), (sa->cbuf2BufSize - sa->cbuf2Len), + &plen)) { + + /* check of cbuf2Len done in saDoG2P, phones skipped if needed */ + if (plen > 255) { + PICODBG_WARN(("maximum number of phones exceeded (%d), skipping", + plen)); + plen = 255; + } + + /* set item head, info1, info2 unchanged */ + sa->headx[ind].head.type = PICODATA_ITEM_WORDPHON; + sa->headx[ind].head.len = (picoos_uint8)plen; + sa->headx[ind].cind = sa->cbuf2Len; + sa->cbuf2Len += plen; + PICODBG_DEBUG(("%c item, plen: %d", + PICODATA_ITEM_WORDPHON, plen)); + } else { + PICODBG_WARN(("problem doing g2p")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_PU_IRREG_ITEM, + NULL, NULL); + } + return PICO_OK; +} + + +/* ***********************************************************************/ +/* extract phonemes of an item into a phonBuf */ +/* ***********************************************************************/ + +static pico_status_t saAddPhoneme(register sa_subobj_t *sa, picoos_uint16 pos, picoos_uint16 sym) { + /* picoos_uint8 plane, unshifted; */ + + /* just for debuging */ + /* + unshifted = picotrns_unplane(sym,&plane); + PICODBG_DEBUG(("adding %i/%i (%c on plane %i) at phonBuf[%i]",pos,sym,unshifted,plane,sa->phonWritePos)); + */ + if (PICOTRNS_MAX_NUM_POSSYM <= sa->phonWritePos) { + /* not an error! */ + PICODBG_DEBUG(("couldn't add because phon buffer full")); + return PICO_EXC_BUF_OVERFLOW; + } else { + sa->phonBuf[sa->phonWritePos].pos = pos; + sa->phonBuf[sa->phonWritePos].sym = sym; + sa->phonWritePos++; + return PICO_OK; + } +} + +/* +static pico_status_t saAddStartPhoneme(register sa_subobj_t *sa) { + return saAddPhoneme(sa, PICOTRNS_POS_IGNORE, + (PICOKFST_PLANE_INTERN << 8) + sa->fixedIds->phonStartId); +} + + +static pico_status_t saAddTermPhoneme(register sa_subobj_t *sa) { + return saAddPhoneme(sa, PICOTRNS_POS_IGNORE, + (PICOKFST_PLANE_INTERN << 8) + sa->fixedIds->phonTermId); +} + +*/ + +static pico_status_t saExtractPhonemes(register picodata_ProcessingUnit this, + register sa_subobj_t *sa, picoos_uint16 pos, + picodata_itemhead_t* head, const picoos_uint8* content) +{ + pico_status_t rv= PICO_OK; + picoos_uint8 i; + picoos_int16 fstSymbol; +#if defined(PICO_DEBUG) + picoos_char msgstr[SA_MSGSTR_SIZE]; +#endif + + PICODBG_TRACE(("doing item %s", + picodata_head_to_string(head,msgstr,SA_MSGSTR_SIZE))); + /* + Items considered in a transduction are WORDPHON item. its starting offset within the inBuf is given as + 'pos'. + Elements that go into the transduction receive "their" position in the buffer. + */ + sa->phonWritePos = 0; + /* WORDPHON(POS,WACC)phon */ + rv = saAddPhoneme(sa, PICOTRNS_POS_IGNORE, + (PICOKFST_PLANE_INTERN << 8) + sa->fixedIds->phonStartId); + for (i = 0; i < head->len; i++) { + fstSymbol = /* (PICOKFST_PLANE_PHONEMES << 8) + */content[i]; + /* */ + PICODBG_TRACE(("adding phoneme %c",fstSymbol)); + rv = saAddPhoneme(sa, pos+PICODATA_ITEM_HEADSIZE+i, fstSymbol); + } + rv = saAddPhoneme(sa, PICOTRNS_POS_IGNORE, + (PICOKFST_PLANE_INTERN << 8) + sa->fixedIds->phonTermId); + sa->nextReadPos = pos + PICODATA_ITEM_HEADSIZE + head->len; + return rv; +} + + +#define SA_POSSYM_OK 0 +#define SA_POSSYM_OUT_OF_RANGE 1 +#define SA_POSSYM_END 2 +#define SA_POSSYM_INVALID -3 +/* *readPos is the next position in phonBuf to be read, and *writePos is the first position not to be read (may be outside + * buf). + * 'rangeEnd' is the first possym position outside the desired range. + * Possible return values: + * SA_POSSYM_OK : 'pos' and 'sym' are set to the read possym, *readPos is advanced + * SA_POSSYM_OUT_OF_RANGE : pos is out of range. 'pos' is set to that of the read possym, 'sym' is undefined + * SA_POSSYM_UNDERFLOW : no more data in buf. 'pos' is set to PICOTRNS_POS_INVALID, 'sym' is undefined + * SA_POSSYM_INVALID : "strange" pos. 'pos' is set to PICOTRNS_POS_INVALID, 'sym' is undefined + */ +static pico_status_t getNextPosSym(sa_subobj_t * sa, picoos_int16 * pos, picoos_int16 * sym, + picoos_int16 rangeEnd) { + /* skip POS_IGNORE */ + while ((sa->phonReadPos < sa->phonWritePos) && (PICOTRNS_POS_IGNORE == sa->phonBuf[sa->phonReadPos].pos)) { + PICODBG_DEBUG(("ignoring phone at sa->phonBuf[%i] because it has pos==IGNORE",sa->phonReadPos)); + sa->phonReadPos++; + } + if ((sa->phonReadPos < sa->phonWritePos)) { + *pos = sa->phonBuf[sa->phonReadPos].pos; + if ((PICOTRNS_POS_INSERT == *pos) || ((0 <= *pos) && (*pos < rangeEnd))) { + *sym = sa->phonBuf[sa->phonReadPos++].sym; + return SA_POSSYM_OK; + } else if (*pos < 0){ /* *pos is "strange" (e.g. POS_INVALID) */ + return SA_POSSYM_INVALID; + } else { + return SA_POSSYM_OUT_OF_RANGE; + } + } else { + /* no more possyms to read */ + *pos = PICOTRNS_POS_INVALID; + return SA_POSSYM_END; + } +} + + + + +/* ***********************************************************************/ +/* saStep function */ +/* ***********************************************************************/ + +/* +complete phrase processed in one step, if not fast enough -> rework + +init, collect into internal buffer, process, and then feed to +output buffer + +init state: INIT ext ext +state trans: in hc1 hc2 out + +INIT | putItem = 0 0 +1 | BUSY -> COLL (put B-SBEG item, + set do-init to false) + + inspace-ok-hc1 + needs-more-items-(phrase-or-flush) +COLL1 |getItems -n +n 0 1 | ATOMIC -> PPOSD (got items, + if flush set do-init) +COLL2 |getItems -n +n 1 0 | ATOMIC -> PPOSD (got items, forced) +COLL3 |getItems -n +n 1 1 | IDLE (got items, need more) +COLL4 |getItems = = 1 1 | IDLE (got no items) + +PPOSD | posd = ~n~n | BUSY -> PWP (posd done) +PWP | lex/g2p = ~n-n 0+n | BUSY -> PPHR (lex/g2p done) +PPHR | phr = -n 0 +m=n | BUSY -> PACC (phr done, m>=n) +PACC | acc = 0 0 ~m=n | BUSY -> FEED (acc done) + + doinit-flag +FEED | putItems 0 0 0 -m-n +m 0 | BUSY -> COLL (put items) +FEED | putItems 0 0 0 -m-n +m 1 | BUSY -> INIT (put items) +FEED | putItems 0 0 0 -d-d +d | OUT_FULL (put some items) +*/ + +static picodata_step_result_t saStep(register picodata_ProcessingUnit this, + picoos_int16 mode, + picoos_uint16 *numBytesOutput) { + register sa_subobj_t *sa; + pico_status_t rv = PICO_OK; + pico_status_t rvP = PICO_OK; + picoos_uint16 blen = 0; + picoos_uint16 clen = 0; + picoos_uint16 i; + picoklex_Lex lex; + + + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + sa = (sa_subobj_t *) this->subObj; + mode = mode; /* avoid warning "var not used in this function"*/ + *numBytesOutput = 0; + while (1) { /* exit via return */ + PICODBG_DEBUG(("doing state %i, hLen|c1Len|c2Len: %d|%d|%d", + sa->procState, sa->headxLen, sa->cbuf1Len, + sa->cbuf2Len)); + + switch (sa->procState) { + + /* *********************************************************/ + /* collect state: get item(s) from charBuf and store in + * internal buffers, need a complete punctuation-phrase + */ + case SA_STEPSTATE_COLLECT: + + while (sa->inspaceok && sa->needsmoreitems + && (PICO_OK == + (rv = picodata_cbGetItem(this->cbIn, sa->tmpbuf, + PICOSA_MAXITEMSIZE, &blen)))) { + rvP = picodata_get_itemparts(sa->tmpbuf, + PICOSA_MAXITEMSIZE, + &(sa->headx[sa->headxLen].head), + &(sa->cbuf1[sa->cbuf1Len]), + sa->cbuf1BufSize-sa->cbuf1Len, + &clen); + if (rvP != PICO_OK) { + PICODBG_ERROR(("problem getting item parts")); + picoos_emRaiseException(this->common->em, rvP, + NULL, NULL); + return PICODATA_PU_ERROR; + } + + /* if CMD(...FLUSH...) -> PUNC(...FLUSH...), + construct PUNC-FLUSH item in headx */ + if ((sa->headx[sa->headxLen].head.type == + PICODATA_ITEM_CMD) && + (sa->headx[sa->headxLen].head.info1 == + PICODATA_ITEMINFO1_CMD_FLUSH)) { + sa->headx[sa->headxLen].head.type = + PICODATA_ITEM_PUNC; + sa->headx[sa->headxLen].head.info1 = + PICODATA_ITEMINFO1_PUNC_FLUSH; + sa->headx[sa->headxLen].head.info2 = + PICODATA_ITEMINFO2_PUNC_SENT_T; + sa->headx[sa->headxLen].head.len = 0; + } + + /* convert opening phoneme command to WORDPHON + * and assign user-POS XX to it (Bug 432) */ + sa->headx[sa->headxLen].cind = sa->cbuf1Len; + /* maybe overwritten later */ + if ((sa->headx[sa->headxLen].head.type == + PICODATA_ITEM_CMD) && + (sa->headx[sa->headxLen].head.info1 == + PICODATA_ITEMINFO1_CMD_PHONEME)&& + (sa->headx[sa->headxLen].head.info2 == + PICODATA_ITEMINFO2_CMD_START)) { + picoos_uint8 i; + picoos_uint8 wordsep = picoktab_getWordboundID(sa->tabphones); + PICODBG_INFO(("wordsep id is %i",wordsep)); + sa->headx[sa->headxLen].head.type = PICODATA_ITEM_WORDPHON; + sa->headx[sa->headxLen].head.info1 = PICODATA_POS_XX; + sa->headx[sa->headxLen].head.info2 = PICODATA_ITEMINFO2_NA; + /* cut off additional words */ + i = 0; + while ((i < sa->headx[sa->headxLen].head.len) && (wordsep != sa->cbuf1[sa->headx[sa->headxLen].cind+i])) { + PICODBG_INFO(("accepting phoneme %i",sa->cbuf1[sa->headx[sa->headxLen].cind+i])); + + i++; + } + if (i < sa->headx[sa->headxLen].head.len) { + PICODBG_INFO(("cutting off superfluous phonetic words at %i",i)); + sa->headx[sa->headxLen].head.len = i; + } + } + + /* check/set needsmoreitems */ + if (sa->headx[sa->headxLen].head.type == + PICODATA_ITEM_PUNC) { + sa->needsmoreitems = FALSE; + } + + /* check/set inspaceok, keep spare slot for forcing */ + if ((sa->headxLen >= (PICOSA_MAXNR_HEADX - 2)) || + ((sa->cbuf1BufSize - sa->cbuf1Len) < + PICOSA_MAXITEMSIZE)) { + sa->inspaceok = FALSE; + } + + if (clen > 0) { + sa->headx[sa->headxLen].cind = sa->cbuf1Len; + sa->cbuf1Len += clen; + } else { + sa->headx[sa->headxLen].cind = 0; + } + sa->headxLen++; + } + + if (!sa->needsmoreitems) { + /* 1, phrase buffered */ + sa->procState = SA_STEPSTATE_PROCESS_POSD; + return PICODATA_PU_ATOMIC; + } else if (!sa->inspaceok) { + /* 2, forced phrase end */ + /* at least one slot is still free, use it to + force a trailing PUNC item */ + sa->headx[sa->headxLen].head.type = PICODATA_ITEM_PUNC; + sa->headx[sa->headxLen].head.info1 = + PICODATA_ITEMINFO1_PUNC_PHRASEEND; + sa->headx[sa->headxLen].head.info2 = + PICODATA_ITEMINFO2_PUNC_PHRASE_FORCED; + sa->headx[sa->headxLen].head.len = 0; + sa->needsmoreitems = FALSE; /* not really needed for now */ + sa->headxLen++; + PICODBG_WARN(("forcing phrase end, added PUNC_PHRASEEND")); + picoos_emRaiseWarning(this->common->em, + PICO_WARN_FALLBACK, NULL, + (picoos_char *)"forced phrase end"); + sa->procState = SA_STEPSTATE_PROCESS_POSD; + return PICODATA_PU_ATOMIC; + } else if (rv == PICO_EOF) { + /* 3, 4 */ + return PICODATA_PU_IDLE; + } else if ((rv == PICO_EXC_BUF_UNDERFLOW) || + (rv == PICO_EXC_BUF_OVERFLOW)) { + /* error, no valid item in cb (UNDER) */ + /* or tmpbuf not large enough, not possible (OVER) */ + /* no exception raised, left for ctrl to handle */ + PICODBG_ERROR(("buffer under/overflow, rv: %d", rv)); + return PICODATA_PU_ERROR; + } else { + /* error, only possible if cbGetItem implementation + changes without this function being adapted*/ + PICODBG_ERROR(("untreated return value, rv: %d", rv)); + return PICODATA_PU_ERROR; + } + break; + + + /* *********************************************************/ + /* process posd state: process items in headx/cbuf1 + * and change in place + */ + case SA_STEPSTATE_PROCESS_POSD: + /* ensure there is an item in inBuf */ + if (sa->headxLen > 0) { + /* we have a phrase in headx, cbuf1 (can be + single PUNC item without POS), do pos disamb */ + if (PICO_OK != saDisambPos(this, sa)) { + picoos_emRaiseException(this->common->em, + PICO_ERR_OTHER, NULL, NULL); + return PICODATA_PU_ERROR; + } + sa->procState = SA_STEPSTATE_PROCESS_WPHO; + + } else if (sa->headxLen == 0) { /* no items in inBuf */ + PICODBG_WARN(("no items in inBuf")); + sa->procState = SA_STEPSTATE_COLLECT; + return PICODATA_PU_BUSY; + } + +#if defined (PICO_DEBUG) + if (1) { + picoos_uint8 i, j, ittype; + for (i = 0; i < sa->headxLen; i++) { + ittype = sa->headx[i].head.type; + PICODBG_INFO_CTX(); + PICODBG_INFO_MSG(("sa-d: (")); + PICODBG_INFO_MSG(("'%c',", ittype)); + if ((32 <= sa->headx[i].head.info1) && + (sa->headx[i].head.info1 < 127) && + (ittype != PICODATA_ITEM_WORDGRAPH) && + (ittype != PICODATA_ITEM_WORDINDEX)) { + PICODBG_INFO_MSG(("'%c',",sa->headx[i].head.info1)); + } else { + PICODBG_INFO_MSG(("%3d,", sa->headx[i].head.info1)); + } + if ((32 <= sa->headx[i].head.info2) && + (sa->headx[i].head.info2 < 127)) { + PICODBG_INFO_MSG(("'%c',",sa->headx[i].head.info2)); + } else { + PICODBG_INFO_MSG(("%3d,", sa->headx[i].head.info2)); + } + PICODBG_INFO_MSG(("%3d)", sa->headx[i].head.len)); + + for (j = 0; j < sa->headx[i].head.len; j++) { + if ((ittype == PICODATA_ITEM_WORDGRAPH) || + (ittype == PICODATA_ITEM_CMD)) { + PICODBG_INFO_MSG(("%c", + sa->cbuf1[sa->headx[i].cind+j])); + } else { + PICODBG_INFO_MSG(("%4d", + sa->cbuf1[sa->headx[i].cind+j])); + } + } + PICODBG_INFO_MSG(("\n")); + } + } +#endif + + break; + + + /* *********************************************************/ + /* process wpho state: process items in headx/cbuf1 and modify + * headx in place and fill cbuf2 + */ + case SA_STEPSTATE_PROCESS_WPHO: + /* ensure there is an item in inBuf */ + if (sa->headxLen > 0) { + /* we have a phrase in headx, cbuf1 (can be single + PUNC item), do lex lookup, g2p, or copy */ + + /* check if cbuf2 is empty as it should be */ + if (sa->cbuf2Len > 0) { + /* enforce emptyness */ + PICODBG_WARN(("forcing empty cbuf2, discarding buf")); + picoos_emRaiseWarning(this->common->em, + PICO_WARN_PU_DISCARD_BUF, + NULL, NULL); + } + + /* cbuf2 overflow avoided in saGrapheme*, saLexInd*, + saCopyItem*, phones skipped if needed */ + for (i = 0; i < sa->headxLen; i++) { + switch (sa->headx[i].head.type) { + case PICODATA_ITEM_WORDGRAPH: + if (PICO_OK != saGraphemeToPhoneme(this, sa, + i)) { + /* not possible, phones skipped if needed */ + picoos_emRaiseException(this->common->em, + PICO_ERR_OTHER, + NULL, NULL); + return PICODATA_PU_ERROR; + } + break; + case PICODATA_ITEM_WORDINDEX: + if (0 == sa->headx[i].head.info2) { + lex = sa->lex; + } else { + lex = sa->ulex[sa->headx[i].head.info2-1]; + } + if (PICO_OK != saLexIndLookup(this, sa, lex, i)) { + /* not possible, phones skipped if needed */ + picoos_emRaiseException(this->common->em, + PICO_ERR_OTHER, + NULL, NULL); + return PICODATA_PU_ERROR; + } + break; + default: + /* copy item unmodified, ie. headx untouched, + content from cbuf1 to cbuf2 */ + if (PICO_OK != saCopyItemContent1to2(this, sa, + i)) { + /* not possible, phones skipped if needed */ + picoos_emRaiseException(this->common->em, + PICO_ERR_OTHER, + NULL, NULL); + return PICODATA_PU_ERROR; + } + break; + } + } + /* set cbuf1 to empty */ + sa->cbuf1Len = 0; + sa->procState = SA_STEPSTATE_PROCESS_TRNS_PARSE; + + } else if (sa->headxLen == 0) { /* no items in inBuf */ + PICODBG_WARN(("no items in inBuf")); + sa->procState = SA_STEPSTATE_COLLECT; + return PICODATA_PU_BUSY; + } + +#if defined (PICO_DEBUG) + if (1) { + picoos_uint8 i, j, ittype; + for (i = 0; i < sa->headxLen; i++) { + ittype = sa->headx[i].head.type; + PICODBG_INFO_CTX(); + PICODBG_INFO_MSG(("sa-g: (")); + PICODBG_INFO_MSG(("'%c',", ittype)); + if ((32 <= sa->headx[i].head.info1) && + (sa->headx[i].head.info1 < 127) && + (ittype != PICODATA_ITEM_WORDPHON)) { + PICODBG_INFO_MSG(("'%c',",sa->headx[i].head.info1)); + } else { + PICODBG_INFO_MSG(("%3d,", sa->headx[i].head.info1)); + } + if ((32 <= sa->headx[i].head.info2) && + (sa->headx[i].head.info2 < 127)) { + PICODBG_INFO_MSG(("'%c',",sa->headx[i].head.info2)); + } else { + PICODBG_INFO_MSG(("%3d,", sa->headx[i].head.info2)); + } + PICODBG_INFO_MSG(("%3d)", sa->headx[i].head.len)); + + for (j = 0; j < sa->headx[i].head.len; j++) { + if ((ittype == PICODATA_ITEM_CMD)) { + PICODBG_INFO_MSG(("%c", + sa->cbuf2[sa->headx[i].cind+j])); + } else { + PICODBG_INFO_MSG(("%4d", + sa->cbuf2[sa->headx[i].cind+j])); + } + } + PICODBG_INFO_MSG(("\n")); + } + } +#endif + + break; + + + /* *********************************************************/ + /* transduction parse state: extract phonemes of item in internal outBuf */ + case SA_STEPSTATE_PROCESS_TRNS_PARSE: + + PICODBG_DEBUG(("transduce item (bot, remain): (%d, %d)", + sa->headxBottom, sa->headxLen)); + + /* check for termination condition first */ + if (0 == sa->headxLen) { + /* reset headx, cbuf2 */ + sa->headxBottom = 0; + sa->cbuf2Len = 0; + /* reset collect state support variables */ + sa->inspaceok = TRUE; + sa->needsmoreitems = TRUE; + + sa->procState = SA_STEPSTATE_COLLECT; + return PICODATA_PU_BUSY; + } + + sa->procState = SA_STEPSTATE_FEED; + /* copy item unmodified */ + rv = picodata_put_itemparts( + &(sa->headx[sa->headxBottom].head), + &(sa->cbuf2[sa->headx[sa->headxBottom].cind]), + sa->headx[sa->headxBottom].head.len, sa->tmpbuf, + PICOSA_MAXITEMSIZE, &blen); + + if (PICODATA_ITEM_WORDPHON == sa->headx[sa->headxBottom].head.type) { + PICODBG_DEBUG(("PARSE found WORDPHON")); + rv = saExtractPhonemes(this, sa, 0, &(sa->headx[sa->headxBottom].head), + &(sa->cbuf2[sa->headx[sa->headxBottom].cind])); + if (PICO_OK == rv) { + PICODBG_DEBUG(("PARSE successfully returned from phoneme extraction")); + sa->procState = SA_STEPSTATE_PROCESS_TRNS_FST; + } else { + PICODBG_WARN(("PARSE phone extraction returned exception %i, output WORDPHON untransduced",rv)); + } + } else { + PICODBG_DEBUG(("PARSE found other item, just copying")); + } + if (SA_STEPSTATE_FEED == sa->procState) { + PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG], + (picoos_uint8 *)"sa-p: ", + sa->tmpbuf, PICOSA_MAXITEMSIZE); + + } + + /* consume item */ + sa->headxBottom++; + sa->headxLen--; + + break; + + /* *********************************************************/ + /* transduce state: copy item in internal outBuf to tmpBuf and transduce */ + case SA_STEPSTATE_PROCESS_TRNS_FST: + + + + + + /* if no word-level FSTs: doing trivial syllabification instead */ + if (0 == sa->numFsts) { + PICODBG_DEBUG(("doing trivial sylabification with %i phones", sa->phonWritePos)); +#if defined(PICO_DEBUG) + { + PICODBG_INFO_CTX(); + PICODBG_INFO_MSG(("sa trying to trivially syllabify: ")); + PICOTRNS_PRINTSYMSEQ(this->voice->kbArray[PICOKNOW_KBID_DBG], sa->phonBuf, sa->phonWritePos); + PICODBG_INFO_MSG(("\n")); + } +#endif + + picotrns_trivial_syllabify(sa->tabphones, sa->phonBuf, + sa->phonWritePos, sa->phonBufOut, + &sa->phonWritePos,PICOTRNS_MAX_NUM_POSSYM); + PICODBG_DEBUG(("returned from trivial sylabification with %i phones", sa->phonWritePos)); +#if defined(PICO_DEBUG) + { + PICODBG_INFO_CTX(); + PICODBG_INFO_MSG(("sa returned from syllabification: ")); + PICOTRNS_PRINTSYMSEQ(this->voice->kbArray[PICOKNOW_KBID_DBG], sa->phonBufOut, sa->phonWritePos); + PICODBG_INFO_MSG(("\n")); + } +#endif + + /* eliminate deep epsilons */ + PICODBG_DEBUG(("doing epsilon elimination with %i phones", sa->phonWritePos)); + picotrns_eliminate_epsilons(sa->phonBufOut, + sa->phonWritePos, sa->phonBuf, + &sa->phonWritePos,PICOTRNS_MAX_NUM_POSSYM); + PICODBG_DEBUG(("returning from epsilon elimination with %i phones", sa->phonWritePos)); + sa->phonReadPos = 0; + sa->phonesTransduced = 1; + sa->procState = SA_STEPSTATE_FEED; + break; + } + + /* there are word-level FSTs */ + /* termination condition first */ + if (sa->curFst >= sa->numFsts) { + /* reset for next transduction */ + sa->curFst = 0; + sa->phonReadPos = 0; + sa->phonesTransduced = 1; + sa->procState = SA_STEPSTATE_FEED; + break; + } + + /* transduce from phonBufIn to PhonBufOut */ + { + + picoos_uint32 nrSteps; +#if defined(PICO_DEBUG) + { + PICODBG_INFO_CTX(); + PICODBG_INFO_MSG(("sa trying to transduce: ")); + PICOTRNS_PRINTSYMSEQ(this->voice->kbArray[PICOKNOW_KBID_DBG], sa->phonBuf, sa->phonWritePos); + PICODBG_INFO_MSG(("\n")); + } +#endif + picotrns_transduce(sa->fst[sa->curFst], FALSE, + picotrns_printSolution, sa->phonBuf, sa->phonWritePos, sa->phonBufOut, + &sa->phonWritePos, + PICOTRNS_MAX_NUM_POSSYM, sa->altDescBuf, + sa->maxAltDescLen, &nrSteps); +#if defined(PICO_DEBUG) + { + PICODBG_INFO_CTX(); + PICODBG_INFO_MSG(("sa returned from transduction: ")); + PICOTRNS_PRINTSYMSEQ(this->voice->kbArray[PICOKNOW_KBID_DBG], sa->phonBufOut, sa->phonWritePos); + PICODBG_INFO_MSG(("\n")); + } +#endif + } + + + + /* + The trasduction output will contain equivalent items i.e. (x,y') for each (x,y) plus inserted deep symbols (-1,d). + In case of deletions, (x,0) might also be omitted... + */ + /* eliminate deep epsilons */ + picotrns_eliminate_epsilons(sa->phonBufOut, + sa->phonWritePos, sa->phonBuf, &sa->phonWritePos,PICOTRNS_MAX_NUM_POSSYM); + sa->phonesTransduced = 1; + + sa->curFst++; + + return PICODATA_PU_ATOMIC; + /* break; */ + + /* *********************************************************/ + /* feed state: copy item in internal outBuf to output charBuf */ + + case SA_STEPSTATE_FEED: + + PICODBG_DEBUG(("FEED")); + + if (sa->phonesTransduced) { + /* replace original phones by transduced */ + picoos_uint16 phonWritePos = PICODATA_ITEM_HEADSIZE; + picoos_uint8 plane; + picoos_int16 sym, pos; + while (SA_POSSYM_OK == (rv = getNextPosSym(sa,&pos,&sym,sa->nextReadPos))) { + PICODBG_TRACE(("FEED inserting phoneme %c into inBuf[%i]",sym,phonWritePos)); + sym = picotrns_unplane(sym, &plane); + PICODBG_ASSERT((PICOKFST_PLANE_PHONEMES == plane)); + sa->tmpbuf[phonWritePos++] = (picoos_uint8) sym; + } + PICODBG_DEBUG(("FEED setting item length to %i",phonWritePos - PICODATA_ITEM_HEADSIZE)); + picodata_set_itemlen(sa->tmpbuf,PICODATA_ITEM_HEADSIZE,phonWritePos - PICODATA_ITEM_HEADSIZE); + if (SA_POSSYM_INVALID == rv) { + PICODBG_ERROR(("FEED unexpected symbol or unexpected end of phoneme list")); + return (picodata_step_result_t)picoos_emRaiseException(this->common->em, PICO_WARN_INCOMPLETE, NULL, NULL); + } + sa->phonesTransduced = 0; + + } /* if (sa->phonesTransduced) */ + + + rvP = picodata_cbPutItem(this->cbOut, sa->tmpbuf, + PICOSA_MAXITEMSIZE, &clen); + + *numBytesOutput += clen; + + PICODBG_DEBUG(("put item, status: %d", rvP)); + + if (rvP == PICO_OK) { + } else if (rvP == PICO_EXC_BUF_OVERFLOW) { + /* try again next time */ + PICODBG_DEBUG(("feeding overflow")); + return PICODATA_PU_OUT_FULL; + } else { + /* error, should never happen */ + PICODBG_ERROR(("untreated return value, rvP: %d", rvP)); + return PICODATA_PU_ERROR; + } + + PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG], + (picoos_uint8 *)"sana: ", + sa->tmpbuf, PICOSA_MAXITEMSIZE); + + sa->procState = SA_STEPSTATE_PROCESS_TRNS_PARSE; + /* return PICODATA_PU_BUSY; */ + break; + + default: + break; + } /* switch */ + + } /* while */ + + /* should be never reached */ + PICODBG_ERROR(("reached end of function")); + picoos_emRaiseException(this->common->em, PICO_ERR_OTHER, NULL, NULL); + return PICODATA_PU_ERROR; +} + +#ifdef __cplusplus +} +#endif + + +/* end */ diff --git a/pico/lib/picosa.h b/pico/lib/picosa.h new file mode 100644 index 0000000..c35da2e --- /dev/null +++ b/pico/lib/picosa.h @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picosa.h + * + * sentence analysis - POS disambiguation - Include file + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + + +/** @addtogroup picosa + * ---------------------------------------------------\n + * Pico Sentence analysis \n + * ---------------------------------------------------\n + * +itemtype, iteminfo1, iteminfo2, content -> TYPE(INFO1,INFO2)content +in the following + +items input +=========== + +processed by sa (POS disambiguation): +- WORDGRAPH(POSes,NA)graph +- WORDINDEX(POSes,NA)POS|1ind1...POSN|indN +- CMD(PICODATA_ITEMINFO1_CMD_FLUSH,PICODATA_ITEMINFO2_NA) + +processed by sa (Phrasing, Accentuation): +- PUNC(PUNCtype,PUNCsubtype) + +unprocessed: +- all other item types are forwarded through the PU without modification: + CMD + + +minimal input size (before processing starts) +================== + +processing (POS disambiguation, g2p, lexind, phrasing, accentuation) +is possible with + +- one punctuation-phrase, consisting of a sequence (see below for + limits) of items terminated by a PUNC item. + +(possible but not implemented: as long as the internal buffer is +empty, non-processed item types can be processed immediately) + +Ensuring terminal PUNC item: +- when reading items from the external buffer a CMD(...FLUSH...) is + converted to a PUNC(...FLUSH...) item +- If needed, a PUNC(PHRASE) is artificially added to ensure a phrase + fits in the PUs memory and processing can start. + + +items processed and output +========================== + +precondition: +CMD(...FLUSH...) already converted to PUNC(...FLUSH...) and trailing +PUNC item enforced if necessary. + +---- +1. PROCESS_POSD: processing input WORDGRAPH or WORDINDEX items, after +POS disambiguation (POSes -> POS), results in a sequence of: + +-> WORDGRAPH(POS,NA)graph +-> WORDINDEX(POS,NA)POS|ind + +---- +2. PROCESS_WPHO: then, after lex-index lookup and G2P in a +sequence of: + +-> WORDPHON(POS,NA)phon + +(phon containing primary and secondary word-level stress) + +---- +3. PROCESS_PHR: then, after processing these WORDPHON items, +together with the trailing PUNC item results in: + +-> BOUND(BOUNDstrength,BOUNDtype) + +being added in the sequence of WORDPHON (respectively inserted instead +of the PUNC). All PUNC, incl PUNC(...FLUSH...) now gone. + +---- +4. PROCESS_ACC: then, after processing the WORDPHON and BOUND items +results in: + +-> WORDPHON(POS,ACC)phon + +A postprocessing step of accentuation is hard-coded in the +accentuation module: In case the whole word does not have any stress +at all (primary or secondary or both) then do the following mapping: + + ACC0 nostress -> ACC0 + ACC1 nostress -> ACC3 + ACC2 nostress -> ACC3 + ACC3 nostress -> ACC3 + +---- +- POS + a single, unambiguous POS + +cf. picodata.h for +- ACC (sentence-level accent (aka prominence)) %d + PICODATA_ACC0 + PICODATA_ACC1 + PICODATA_ACC2 (<- maybe mapped to ACC1, ie. no ACC2 in output) + PICODATA_ACC3 + +- BOUNDstrength %d + PICODATA_ITEMINFO1_BOUND_SBEG (at sentence start) + PICODATA_ITEMINFO1_BOUND_SEND (at sentence end) + PICODATA_ITEMINFO1_BOUND_TERM (replaces a flush) + PICODATA_ITEMINFO1_BOUND_PHR1 (primary boundary) + PICODATA_ITEMINFO1_BOUND_PHR2 (short break) + PICODATA_ITEMINFO1_BOUND_PHR3 (secondary phrase boundary, no break) + PICODATA_ITEMINFO1_BOUND_PHR0 (no break, not produced by sa, not existing + BOUND in item sequence equals PHR0 bound strength) + +- BOUNDtype (created in sa base on punctuation, indicates type of phrase + following the boundary) %d + PICODATA_ITEMINFO2_BOUNDTYPE_P + PICODATA_ITEMINFO2_BOUNDTYPE_T + PICODATA_ITEMINFO2_BOUNDTYPE_Q + PICODATA_ITEMINFO2_BOUNDTYPE_E + + +output sequence (without CMDs): + + = { BOUND(BOUND_SBEG,PHRASEtype) BOUND(BOUND_SEND,..)} BOUND(BOUND_TERM,..) + + + = { BOUND(BOUND_PHR1|2|3,BOUNDtype) } + + = WORDPHON(POS,ACC)phon { WORDPHON(POS,ACC)phon } + + +Done in later PU: mapping ACC & word-level stress to syllable accent value + ACC0 prim -> 0 + ACC1 prim -> 1 + ACC2 prim -> 2 + ACC3 prim -> 3 + ACC0 sec -> 0 + ACC1 sec -> 4 + ACC2 sec -> 4 + ACC3 sec -> 4 + + +other limitations +================= + +- item size: header plus len=256 (valid for Pico in general) +- see defines below for max nr of items. Item heads plus ref. to contents + buffer are stored in array with fixed size elements. Two restrictions: + - MAXNR_HEADX (max nr elements==items in headx array) + - CONTENTSSIZE (max size of all contents together + */ + + +#ifndef PICOSA_H_ +#define PICOSA_H_ + +#include "picoos.h" +#include "picodata.h" +#include "picorsrc.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* nr item restriction: maximum number of extended item heads in headx */ +#define PICOSA_MAXNR_HEADX 60 +/* nr item restriction: maximum size of all item contents together in cont */ +#define PICOSA_MAXSIZE_CBUF 7680 + +/* maximum length of an item incl. head for input GetItem buffer */ +#define PICOSA_MAXITEMSIZE 260 + + +picodata_ProcessingUnit picosa_newSentAnaUnit( + picoos_MemoryManager mm, + picoos_Common common, + picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, + picorsrc_Voice voice); + +#ifdef __cplusplus +} +#endif + + +#endif /*PICOSA_H_*/ diff --git a/pico/lib/picosig.c b/pico/lib/picosig.c new file mode 100644 index 0000000..6256dea --- /dev/null +++ b/pico/lib/picosig.c @@ -0,0 +1,1287 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picosig.c + * + * Signal Generation PU - Implementation + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include "picoos.h" +#include "picodsp.h" +#include "picosig2.h" +#include "picodata.h" +#include "picosig.h" +#include "picodbg.h" +#include "picokpdf.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +#define PICOSIG_IN_BUFF_SIZE PICODATA_BUFSIZE_SIG /*input buffer size for SIG */ +#define PICOSIG_OUT_BUFF_SIZE PICODATA_BUFSIZE_SIG /*output buffer size for SIG*/ + +#define PICOSIG_COLLECT 0 +#define PICOSIG_SCHEDULE 1 +#define PICOSIG_PLAY 2 +#define PICOSIG_PROCESS 3 +#define PICOSIG_FEED 4 + +/*---------------------------------------------------------- + // Internal function declarations + //---------------------------------------------------------*/ + +static picodata_step_result_t sigStep(register picodata_ProcessingUnit this, + picoos_int16 mode, picoos_uint16 * numBytesOutput); + +/*---------------------------------------------------------- + // Name : sig_subobj + // Function: subobject definition for the sig processing + // Shortcut: sig + //---------------------------------------------------------*/ +typedef struct sig_subobj +{ + /*----------------------PU voice management------------------------------*/ + /* picorsrc_Voice voice; */ + /*----------------------PU state management------------------------------*/ + picoos_uint8 procState; /* where to take up work at next processing step */ + picoos_uint8 retState; /* where to return after next processing step */ + picoos_uint8 needMoreInput; /* more data necessary to start processing */ + /*----------------------PU input management------------------------------*/ + picoos_uint8 inBuf[PICOSIG_IN_BUFF_SIZE]; /* internal input buffer */ + picoos_uint16 inBufSize;/* actually allocated size */ + picoos_uint16 inReadPos, inWritePos; /* next pos to read/write from/to inBuf*/ + /*Input audio file management*/ + picoos_char sInSDFileName[255]; + picoos_SDFile sInSDFile; + picoos_uint32 sInSDFilePos; + /*----------------------PU output management-----------------------------*/ + picoos_uint8 outBuf[PICOSIG_OUT_BUFF_SIZE]; /* internal output buffer */ + picoos_uint16 outBufSize; /* actually allocated size */ + picoos_uint16 outReadPos, outWritePos; /* next pos to read/write from/to outBuf*/ + picoos_bool outSwitch; /* output destination switch 0:buffer, 1:file*/ + picoos_char sOutSDFileName[255]; /* output file name */ + picoos_SDFile sOutSDFile; /* output file handle */ + picoos_single fSampNorm; /* running normalization factor */ + picoos_uint32 nNumFrame; /* running count for frame number in output items */ + /*---------------------- other working variables ---------------------------*/ + picoos_uint8 innerProcState; /*where to take up work at next processing step*/ + /*-----------------------Definition of the local storage for this PU--------*/ + sig_innerobj_t sig_inner; + picoos_single pMod; /*pitch modifier*/ + picoos_single vMod; /*Volume modifier*/ + picoos_single sMod; /*speaker modifier*/ + /*knowledge bases */ + picokpdf_PdfMUL pdflfz, pdfmgc; + picoos_uint32 scmeanpowLFZ, scmeanpowMGC; + picoos_uint32 scmeanLFZ, scmeanMGC; + picokpdf_PdfPHS pdfphs; + +} sig_subobj_t; + +/* ****************************************************************************** + * generic PU management + ********************************************************************************/ + +/** + * initialization of the PU (processing unit) + * @param this : sig PU object + * @return PICO_OK : init ok + * @return PICO_ERR_OTHER : init failed + * @callgraph + * @callergraph + */ +static pico_status_t sigInitialize(register picodata_ProcessingUnit this, picoos_int32 resetMode) +{ + sig_subobj_t *sig_subObj; + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + sig_subObj = (sig_subobj_t *) this->subObj; + sig_subObj->inBufSize = PICOSIG_IN_BUFF_SIZE; + sig_subObj->outBufSize = PICOSIG_OUT_BUFF_SIZE; + sig_subObj->inReadPos = 0; + sig_subObj->inWritePos = 0; + sig_subObj->outReadPos = 0; + sig_subObj->outWritePos = 0; + sig_subObj->needMoreInput = 0; + sig_subObj->procState = PICOSIG_COLLECT; + sig_subObj->retState = PICOSIG_COLLECT; + sig_subObj->innerProcState = 0; + sig_subObj->nNumFrame = 0; + + /*----------------------------------------------------------------- + * MANAGE Item I/O control management + ------------------------------------------------------------------*/ + sig_subObj->sInSDFile = NULL; + sig_subObj->sInSDFilePos = 0; + sig_subObj->sInSDFileName[0] = '\0'; + sig_subObj->outSwitch = 0; /*PU sends output to buffer (nextPU)*/ + sig_subObj->sOutSDFile = NULL; + sig_subObj->sOutSDFileName[0] = '\0'; + sig_subObj->nNumFrame = 0; + + /*----------------------------------------------------------------- + * MANAGE LINGWARE INITIALIZATION IF NEEDED + ------------------------------------------------------------------*/ + if (resetMode == PICO_RESET_FULL) { + /*not done when resetting SOFT*/ + sig_subObj->pdfmgc = picokpdf_getPdfMUL( + this->voice->kbArray[PICOKNOW_KBID_PDF_MGC]); + sig_subObj->pdflfz = picokpdf_getPdfMUL( + this->voice->kbArray[PICOKNOW_KBID_PDF_LFZ]); + sig_subObj->pdfphs = picokpdf_getPdfPHS( + this->voice->kbArray[PICOKNOW_KBID_PDF_PHS]); + + sig_subObj->scmeanpowLFZ = sig_subObj->pdflfz->bigpow + - sig_subObj->pdflfz->meanpow; + sig_subObj->scmeanpowMGC = sig_subObj->pdfmgc->bigpow + - sig_subObj->pdfmgc->meanpow; + sig_subObj->scmeanLFZ = (1 << (picoos_uint32) sig_subObj->scmeanpowLFZ); + sig_subObj->scmeanMGC = (1 << (picoos_uint32) sig_subObj->scmeanpowMGC); + sig_subObj->fSampNorm = PICOSIG_NORM1 * sig_subObj->pdfmgc->amplif; + /*----------------------------------------------------------------- + * Initialize memory for DSP + * ------------------------------------------------------------------*/ + sigDspInitialize(&(sig_subObj->sig_inner), resetMode); + /*----------------------------------------------------------------- + * Initialize modifiers + * ------------------------------------------------------------------*/ + /*pitch , volume , speaker modifiers*/ + sig_subObj->pMod = 1.0f; + sig_subObj->vMod = 0.5f; + sig_subObj->sMod = 1.0f; + } else { + /*----------------------------------------------------------------- + * Initialize memory for DSP + * ------------------------------------------------------------------*/ + sigDspInitialize(&(sig_subObj->sig_inner), resetMode); + } + + + return PICO_OK; +}/*sigInitialize*/ + +/** + * terminates the PU (processing unit) + * @param this : sig PU object + * @return PICO_OK : termination ok + * @return PICO_ERR_OTHER : termination failed + * @callgraph + * @callergraph + */ +static pico_status_t sigTerminate(register picodata_ProcessingUnit this) +{ + + sig_subobj_t *sig_subObj; + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + sig_subObj = (sig_subobj_t *) this->subObj; + + return PICO_OK; +}/*sigTerminate*/ + +/** + * deallocates the PU (processing unit) sub object + * @param this : sig PU object + * @param mm : the engine memory manager + * @return PICO_OK : deallocation ok + * @return PICO_ERR_OTHER : deallocation failed + * @callgraph + * @callergraph + */ +static pico_status_t sigSubObjDeallocate(register picodata_ProcessingUnit this, + picoos_MemoryManager mm) +{ + sig_subobj_t *sig_subObj; + if ((NULL == this) || ((this)->subObj == NULL)) { + return PICO_ERR_OTHER; + } + sig_subObj = (sig_subobj_t *) (this)->subObj; + + if (sig_subObj->sInSDFile != NULL) { + picoos_sdfCloseIn(this->common, &(sig_subObj->sInSDFile)); + sig_subObj->sInSDFile = NULL; + sig_subObj->sInSDFileName[0] = '\0'; + } + + if (sig_subObj->sOutSDFile != NULL) { + picoos_sdfCloseOut(this->common, &(sig_subObj->sOutSDFile)); + sig_subObj->sOutSDFile = NULL; + sig_subObj->sOutSDFileName[0] = '\0'; + } + + sigDeallocate(mm, &(sig_subObj->sig_inner)); + + picoos_deallocate(this->common->mm, (void *) &this->subObj); + + return PICO_OK; +}/*sigSubObjDeallocate*/ + +/** + * creates a new sig processing unit + * @param mm : the engine memory manager + * @param common : the engine common object + * @param cbIn : the PU input buffer + * @param cbOut : the PU output buffer + * @param voice : the voice descriptor object + * @return a valid PU handle if creation is OK + * @return NULL if creation is !=OK + * @callgraph + * @callergraph + */ +picodata_ProcessingUnit picosig_newSigUnit(picoos_MemoryManager mm, + picoos_Common common, picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, picorsrc_Voice voice) +{ + sig_subobj_t *sig_subObj; + + picodata_ProcessingUnit this = picodata_newProcessingUnit(mm, common, cbIn, + cbOut, voice); + if (NULL == this) { + return NULL; + } + this->initialize = sigInitialize; + + PICODBG_DEBUG(("picosig_newSigUnit -- creating SIG PU")); + /*Init function pointers*/ + this->step = sigStep; + this->terminate = sigTerminate; + this->subDeallocate = sigSubObjDeallocate; + /*sub obj allocation*/ + this->subObj = picoos_allocate(mm, sizeof(sig_subobj_t)); + + if (NULL == this->subObj) { + PICODBG_ERROR(("Error in Sig Object allocation")); + picoos_deallocate(mm, (void *) &this); + return NULL; + } + sig_subObj = (sig_subobj_t *) this->subObj; + + /*----------------------------------------------------------------- + * Allocate memory for DSP inner algorithms + * ------------------------------------------------------------------*/ + if (sigAllocate(mm, &(sig_subObj->sig_inner)) != 0) { + PICODBG_ERROR(("Error in Sig Sub Object Allocation")); + picoos_deallocate(mm, (void *) &this); + return NULL; + } + + /*----------------------------------------------------------------- + * Initialize memory for DSP (this may be re-used elsewhere, e.g.Reset) + * ------------------------------------------------------------------*/ + if (PICO_OK != sigInitialize(this, PICO_RESET_FULL)) { + PICODBG_ERROR(("Error in iSig Sub Object initialization")); + sigDeallocate(mm, &(sig_subObj->sig_inner)); + picoos_deallocate(mm, (void *) &this); + return NULL; + }PICODBG_DEBUG(("SIG PU creation succeded!!")); + return this; +}/*picosig_newSigUnit*/ + +/** + * pdf access for phase + * @param this : sig object pointer + * @param phsIndex : index of phase vectot in the pdf + * @param phsVect : pointer to base of array where to store the phase values + * @param numComponents : pointer to the variable to store the number of components + * @return PICO_OK : pdf retrieved + * @return PICO_ERR_OTHER : pdf not retrieved + * @callgraph + * @callergraph + */ +static pico_status_t getPhsFromPdf(register picodata_ProcessingUnit this, + picoos_uint16 phsIndex, picoos_int32 *phsVect, + picoos_int16 *numComponents) +{ + sig_subobj_t *sig_subObj; + picokpdf_PdfPHS pdf; + static int nFrame = 0; + + picoos_uint32 nIndexValue; + picoos_uint8 *nCurrIndexOffset, *nContent; + picoos_uint16 nI; + + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + sig_subObj = (sig_subobj_t *) this->subObj; + pdf = sig_subObj->pdfphs; + /*check incoming index*/ + if (phsIndex >= pdf->numvectors) { + return PICODATA_PU_ERROR; + } + nCurrIndexOffset = ((picoos_uint8*) pdf->indexBase) + phsIndex * sizeof(picoos_uint32); + nIndexValue = (0xFF000000 & ((*(nCurrIndexOffset+3)) << 24)) | (0x00FF0000 & ((*(nCurrIndexOffset+2)) << 16)) | + (0x0000FF00 & ((*(nCurrIndexOffset+1)) << 8)) | (0x000000FF & ((*nCurrIndexOffset))); + nContent = pdf->contentBase; + nContent += nIndexValue; + *numComponents = (picoos_int16) *nContent++; + if (*numComponents>PICODSP_PHASEORDER) { + PICODBG_DEBUG(("WARNING : Frame %d -- Phase vector[%d] Components = %d --> too big\n", nFrame, phsIndex, *numComponents)); + *numComponents = PICODSP_PHASEORDER; + } + for (nI=0; nI<*numComponents; nI++) { + phsVect[nI] = (picoos_int32) *nContent++; + } + for (nI=*numComponents; nIsubObj; + + numinb = numinb; /* avoid warning "var not used in this function"*/ + + /*defaults to 0 for output bytes*/ + *numoutb = 0; + + /*Input buffer contains an item FRAME_PAR*/ + switch (sig_subObj->innerProcState) { + + case 0: + /*--------------------------------------------- + Shifting old values + ---------------------------------------------*/ + for (n_count = 0; n_count < CEPST_BUFF_SIZE-1; n_count++) { + sig_subObj->sig_inner.F0Buff[n_count]=sig_subObj->sig_inner.F0Buff[n_count+1]; + sig_subObj->sig_inner.PhIdBuff[n_count]=sig_subObj->sig_inner.PhIdBuff[n_count+1]; + sig_subObj->sig_inner.VoicingBuff[n_count]=sig_subObj->sig_inner.VoicingBuff[n_count+1]; + sig_subObj->sig_inner.FuVBuff[n_count]=sig_subObj->sig_inner.FuVBuff[n_count+1]; + } + for (n_count = 0; n_count < PHASE_BUFF_SIZE-1; n_count++) { + sig_subObj->sig_inner.VoxBndBuff[n_count]=sig_subObj->sig_inner.VoxBndBuff[n_count+1]; + } + + tmp1 = sig_subObj->sig_inner.CepBuff[0]; + for (n_count = 0; n_count < CEPST_BUFF_SIZE-1; n_count++) { + sig_subObj->sig_inner.CepBuff[n_count]=sig_subObj->sig_inner.CepBuff[n_count+1]; + } + sig_subObj->sig_inner.CepBuff[CEPST_BUFF_SIZE-1]=tmp1; + + tmp1 = sig_subObj->sig_inner.PhsBuff[0]; + for (n_count = 0; n_count < PHASE_BUFF_SIZE-1; n_count++) { + sig_subObj->sig_inner.PhsBuff[n_count]=sig_subObj->sig_inner.PhsBuff[n_count+1]; + } + sig_subObj->sig_inner.PhsBuff[PHASE_BUFF_SIZE-1]=tmp1; + + /*--------------------------------------------- + Frame related initializations + ---------------------------------------------*/ + sig_subObj->sig_inner.prevVoiced_p = sig_subObj->sig_inner.voiced_p; + /*--------------------------------------------- + Get input data from PU buffer in internal buffers + -------------------------------------------------*/ + /*load the phonetic id code*/ + picoos_mem_copy((void *) &sig_subObj->inBuf[inReadPos + + sizeof(picodata_itemhead_t)], /*src*/ + (void *) &tmp_uint16, sizeof(tmp_uint16)); /*dest+size*/ + sig_subObj->sig_inner.PhIdBuff[CEPST_BUFF_SIZE-1] = (picoos_int16) tmp_uint16; /*store into newest*/ + tmp_uint16 = (picoos_int16) sig_subObj->sig_inner.PhIdBuff[0]; /*assign oldest*/ + sig_subObj->sig_inner.phId_p = (picoos_int16) tmp_uint16; /*assign oldest*/ + + /*load pitch values*/ + for (i = 0; i < sig_subObj->pdflfz->ceporder; i++) { + picoos_mem_copy((void *) &(sig_subObj->inBuf[inReadPos + + sizeof(picodata_itemhead_t) + sizeof(tmp_uint16) + 3 + * i * sizeof(tmp_uint16)]), /*src*/ + (void *) &tmp_uint16, sizeof(tmp_uint16)); /*dest+size*/ + + sig_subObj->sig_inner.F0Buff[CEPST_BUFF_SIZE-1] = (picoos_int16) tmp_uint16;/*store into newest*/ + tmp_uint16 = (picoos_int16) sig_subObj->sig_inner.F0Buff[0]; /*assign oldest*/ + + /*convert in float*/ + sig_subObj->sig_inner.F0_p + = (tmp_uint16 ? ((picoos_single) tmp_uint16 + / sig_subObj->scmeanLFZ) : (picoos_single) 0.0); + + if (sig_subObj->sig_inner.F0_p != (picoos_single) 0.0f) { + sig_subObj->sig_inner.F0_p = (picoos_single) exp( + (picoos_single) sig_subObj->sig_inner.F0_p); + + } + /* voicing */ + picoos_mem_copy((void *) &(sig_subObj->inBuf[inReadPos + + sizeof(picodata_itemhead_t) + sizeof(tmp_uint16) + 3 + * i * sizeof(tmp_uint16) + sizeof(tmp_uint16)]),/*src*/ + (void *) &tmp_uint16, sizeof(tmp_uint16)); /*dest+size*/ + + sig_subObj->sig_inner.VoicingBuff[CEPST_BUFF_SIZE-1] = (picoos_int16) tmp_uint16;/*store into newest*/ + tmp_uint16 = (picoos_int16) sig_subObj->sig_inner.VoicingBuff[0]; /*assign oldest*/ + + sig_subObj->sig_inner.voicing = (picoos_single) ((tmp_uint16 + & 0x01) * 8 + (tmp_uint16 & 0x0e) / 2) + / (picoos_single) 15.0f; + + /* unrectified f0 */ + picoos_mem_copy((void *) &(sig_subObj->inBuf[inReadPos + + sizeof(picodata_itemhead_t) + sizeof(tmp_uint16) + 3 + * i * sizeof(tmp_uint16) + 2 * sizeof(tmp_uint16)]),/*src*/ + (void *) &tmp_uint16, sizeof(tmp_uint16)); /*dest+size*/ + + sig_subObj->sig_inner.FuVBuff[CEPST_BUFF_SIZE-1] = (picoos_int16) tmp_uint16;/*store into newest*/ + tmp_uint16 = (picoos_int16) sig_subObj->sig_inner.FuVBuff[0]; /*assign oldest*/ + + sig_subObj->sig_inner.Fuv_p = (picoos_single) tmp_uint16 + / sig_subObj->scmeanLFZ; + sig_subObj->sig_inner.Fuv_p = (picoos_single) EXP((double)sig_subObj->sig_inner.Fuv_p); + } + /*load cep values*/ + offset = inReadPos + sizeof(picodata_itemhead_t) + + sizeof(tmp_uint16) + + 3 * sig_subObj->pdflfz->ceporder * sizeof(tmp_int16); + + tmp1 = sig_subObj->sig_inner.CepBuff[CEPST_BUFF_SIZE-1]; /*store into CURR */ + tmp2 = sig_subObj->sig_inner.CepBuff[0]; /*assign oldest*/ + + for (i = 0; i < sig_subObj->pdfmgc->ceporder; i++) { + picoos_mem_copy((void *) &(sig_subObj->inBuf[offset + i + * sizeof(tmp_int16)]), /*src*/ + (void *) &tmp_int16, sizeof(tmp_int16)); /*dest+size*/ + + tmp1 [i] = (picoos_int32) tmp_int16; + sig_subObj->sig_inner.wcep_pI[i] = (picoos_int32) tmp2[i]; + } + + if (sig_subObj->inBuf[inReadPos+ 3] > sig_subObj->inBuf[inReadPos+ 2]*2 + 8) { + /*load phase values*/ + /*get the index*/ + picoos_mem_copy((void *) &(sig_subObj->inBuf[offset + sig_subObj->pdfmgc->ceporder + * sizeof(tmp_int16)]), /*src*/ + (void *) &tmp_int16, sizeof(tmp_int16)); /*dest+size*/ + + /*store into buffers*/ + tmp1 = sig_subObj->sig_inner.PhsBuff[PHASE_BUFF_SIZE-1]; + /*retrieve values from pdf*/ + getPhsFromPdf(this, tmp_int16, tmp1, &(sig_subObj->sig_inner.VoxBndBuff[PHASE_BUFF_SIZE-1])); + } else { + /* no support for phase found */ + sig_subObj->sig_inner.VoxBndBuff[PHASE_BUFF_SIZE-1] = 0; + } + + /*pitch modifier*/ + sig_subObj->sig_inner.F0_p *= sig_subObj->pMod; + sig_subObj->sig_inner.Fuv_p *= sig_subObj->pMod; + if (sig_subObj->sig_inner.F0_p > 0.0f) { + sig_subObj->sig_inner.voiced_p = 1; + } else { + sig_subObj->sig_inner.voiced_p = 0; + } + sig_subObj->sig_inner.n_available++; + if (sig_subObj->sig_inner.n_available>3) sig_subObj->sig_inner.n_available = 3; + + if (sig_subObj->sig_inner.n_available < 3) { + return PICO_STEP_BUSY; + } + + sig_subObj->innerProcState = 3; + return PICO_STEP_BUSY; + + case 3: + /*Convert from mfcc to power spectrum*/ + save_transition_frame(&(sig_subObj->sig_inner)); + mel_2_lin_lookup(&(sig_subObj->sig_inner), sig_subObj->scmeanpowMGC); + sig_subObj->innerProcState += 1; + return PICO_STEP_BUSY; + + case 4: + /*Reconstruct PHASE SPECTRUM */ + phase_spec2(&(sig_subObj->sig_inner)); + sig_subObj->innerProcState += 1; + return PICO_STEP_BUSY; + + case 5: + /*Prepare Envelope spectrum for inverse FFT*/ + env_spec(&(sig_subObj->sig_inner)); + sig_subObj->innerProcState += 1; + return PICO_STEP_BUSY; + + case 6: + /*Generate the impulse response of the vocal tract */ + impulse_response(&(sig_subObj->sig_inner)); + sig_subObj->innerProcState += 1; + return PICO_STEP_BUSY; + + case 7: + /*Sum up N impulse responses according to excitation */ + td_psola2(&(sig_subObj->sig_inner)); + sig_subObj->innerProcState += 1; + return PICO_STEP_BUSY; + + case 8: + /*Ovladd */ + overlap_add(&(sig_subObj->sig_inner)); + sig_subObj->innerProcState += 1; + return PICO_STEP_BUSY; + + case 9: + /*----------------------------------------- + Save the output FRAME item (0:hop-1) + swap remaining buffer + ---------------------------------------------*/ + n_frames = 2; + *numoutb = 0; + hop_p_half = (sig_subObj->sig_inner.hop_p) / 2; + for (n_count = 0; n_count < n_frames; n_count++) { + sig_subObj->outBuf[outWritePos] + = (picoos_uint8) PICODATA_ITEM_FRAME; + sig_subObj->outBuf[outWritePos + 1] + = (picoos_uint8) (hop_p_half); + sig_subObj->outBuf[outWritePos + 2] + = (picoos_uint8) (sig_subObj->nNumFrame % ((hop_p_half))); + sig_subObj->outBuf[outWritePos + 3] + = (picoos_uint8) sig_subObj->sig_inner.hop_p; + s_data = (picoos_int16 *) &(sig_subObj->outBuf[outWritePos + 4]); + + /*range control and clipping*/ + mlt = (picoos_int32) ((sig_subObj->fSampNorm * sig_subObj->vMod) + * PICODSP_END_FLOAT_NORM); + t1 = &(sig_subObj->sig_inner.WavBuff_p[n_count * (hop_p_half)]); + for (n_i = 0; n_i < hop_p_half; n_i++) { /*Normalization*/ + f_data = *t1++ * mlt; + if (f_data >= 0) + f_data >>= 14; + else + f_data = -(-f_data >> 14); + if (f_data > PICOSIG_MAXAMP) + f_data = PICOSIG_MAXAMP; + if (f_data < PICOSIG_MINAMP) + f_data = PICOSIG_MINAMP; + *s_data = (picoos_int16) (f_data); + s_data++; + } + sig_subObj->nNumFrame = sig_subObj->nNumFrame + 1; + *numoutb += ((picoos_int16) n_i * sizeof(picoos_int16)) + 4; + outWritePos += *numoutb; + }/*end for n_count*/ + /*Swap remaining buffer*/ + cnt = sig_subObj->sig_inner.m2_p - sig_subObj->sig_inner.hop_p; + tmp1 = sig_subObj->sig_inner.WavBuff_p; + tmp2 + = &(sig_subObj->sig_inner.WavBuff_p[sig_subObj->sig_inner.hop_p]); + FAST_DEVICE(cnt,*(tmp1++)=*(tmp2++);) + ; + cnt = sig_subObj->sig_inner.m2_p - (sig_subObj->sig_inner.m2_p + - sig_subObj->sig_inner.hop_p); + FAST_DEVICE(cnt,*(tmp1++)=0;) + ; + sig_subObj->innerProcState = 0; /*reset to step 0*/ + sig_subObj->nNumFrame += 2; + return PICO_OK; + default: + return PICO_ERR_OTHER; + } + return PICO_ERR_OTHER; +}/*sigProcess*/ + +/** + * selects items to be dealth with by this PU + * @param item : pointer to current item head + * @return TRUE : item should be managed + * @return FALSE : item should be passed on next PU + * @remarks item pointed to by *item should be already valid + * @callgraph + * @callergraph + */ +static pico_status_t sig_deal_with(const picoos_uint8 *item) +{ + picodata_itemhead_t head; + pico_status_t s_result; + s_result = FALSE; + head.type = item[0]; + head.info1 = item[1]; + head.info2 = item[2]; + head.len = item[3]; + switch (head.type) { + case PICODATA_ITEM_FRAME_PAR: + /*the only item that is managed by sig, so far, is "FRAME_PAR"*/ + s_result = TRUE; + break; + case PICODATA_ITEM_CMD: + if ((head.info1 == PICODATA_ITEMINFO1_CMD_PLAY) || (head.info1 + == PICODATA_ITEMINFO1_CMD_SAVE) || (head.info1 + == PICODATA_ITEMINFO1_CMD_UNSAVE)) { + if (head.info2 == PICODATA_ITEMINFO2_CMD_TO_SIG) { + return TRUE; + } + } + if ((head.info1 == PICODATA_ITEMINFO1_CMD_PITCH) || (head.info1 + == PICODATA_ITEMINFO1_CMD_VOLUME) || (head.info1 + == PICODATA_ITEMINFO1_CMD_SPEAKER)) { + return TRUE; + } + break; + default: + break; + } + return s_result; +} /*sig_deal_with*/ + +/** + * selects items to be managed as commands by this PU + * @param item : pointer to current item head + * @return TRUE : item should be managed as a command + * @return FALSE : item is not a PU command + * @remarks item pointed to by *item should be already valid + * @callgraph + * @callergraph + */ +static pico_status_t sig_is_command(const picoos_uint8 *item) +{ + picodata_itemhead_t head; + head.type = item[0]; + head.info1 = item[1]; + head.info2 = item[2]; + head.len = item[3]; + switch (head.type) { + case PICODATA_ITEM_CMD: + if ((head.info1 == PICODATA_ITEMINFO1_CMD_PLAY) || (head.info1 + == PICODATA_ITEMINFO1_CMD_SAVE) || (head.info1 + == PICODATA_ITEMINFO1_CMD_UNSAVE)) { + if (head.info2 == PICODATA_ITEMINFO2_CMD_TO_SIG) { + return TRUE; + } + } + if ((head.info1 == PICODATA_ITEMINFO1_CMD_PITCH) || (head.info1 + == PICODATA_ITEMINFO1_CMD_VOLUME) || (head.info1 + == PICODATA_ITEMINFO1_CMD_SPEAKER)) { + return TRUE; + } + break; + default: + break; + } + return FALSE; +} /*sig_is_command*/ + +/** + * performs a step of the sig processing + * @param this : pointer to current PU (Control Unit) + * @param mode : mode for the PU + * @param numBytesOutput : pointer to number of bytes produced (output) + * @param this : pointer to current PU (Control Unit) + * @return one of the "picodata_step_result_t" values + * @callgraph + * @callergraph + */ +static picodata_step_result_t sigStep(register picodata_ProcessingUnit this, + picoos_int16 mode, picoos_uint16 * numBytesOutput) +{ + register sig_subobj_t * sig_subObj; + pico_status_t s_result; + picoos_bool b_res; + pico_status_t s_deal_with; + picoos_uint16 blen; + picoos_uint16 numinb, numoutb; + pico_status_t rv; + picoos_int16 *s_data; + picoos_int16 hop_p_half; + picoos_uint32 n_samp, n_i; + picoos_char s_temp_file_name[255]; + picoos_uint32 n_start, n_fram, n_bytes; + picoos_single f_value; + picoos_uint16 n_value; + picoos_uint32 n_pos; + /*wav file play volume control*/ + picoos_int16 *s_t1; + picoos_int32 sf_data, sf_mlt; + picoos_uint32 sf; + picoos_encoding_t enc; + picoos_uint32 numSamples; + + numinb = 0; + numoutb = 0; + rv = PICO_OK; + s_result = PICO_OK; + + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + sig_subObj = (sig_subobj_t *) this->subObj; + + /*Init number of output bytes*/ + *numBytesOutput = 0; + + mode = mode; /* avoid warning "var not used in this function" */ + + while (1) { /* exit via return */ + + PICODBG_DEBUG(("picosig.sigStep -- doing state %i",sig_subObj->procState)); + + switch (sig_subObj->procState) { + + case PICOSIG_COLLECT: + /* ************** item collector ***********************************/ + /*collecting items from the PU input buffer*/ + s_result = picodata_cbGetItem(this->cbIn, + &(sig_subObj->inBuf[sig_subObj->inWritePos]), + sig_subObj->inBufSize - sig_subObj->inWritePos, &blen); + + PICODBG_DEBUG(("picosig.sigStep -- got item, status: %d",rv)); + + if (s_result == PICO_EOF) { + /*no items available : remain in state 0 and return idle*/ + return PICODATA_PU_IDLE; + } + if ((PICO_OK == s_result) && (blen > 0)) { + /* we now have one item : CHECK IT */ + s_result = picodata_is_valid_item( + &(sig_subObj->inBuf[sig_subObj->inWritePos]), blen); + if (s_result != TRUE) { + PICODBG_DEBUG(("picosig.sigStep -- item is not valid: discard")); + /*Item not valid : remain in state PICOSIG_COLLECT*/ + return PICODATA_PU_BUSY; + } + /*item ok: it could be sent to schedule state*/ + sig_subObj->inWritePos += blen; + sig_subObj->needMoreInput = FALSE; + sig_subObj->procState = PICOSIG_SCHEDULE; + /* uncomment next to split into two steps */ + return PICODATA_PU_ATOMIC; + } + /*no EOF, no OK --> errors : remain in state PICOSIG_COLLECT and return error*/ + return PICODATA_PU_ERROR; + break; + + case PICOSIG_SCHEDULE: + /* *************** item processing ***********************************/ + numinb = PICODATA_ITEM_HEADSIZE + + sig_subObj->inBuf[sig_subObj->inReadPos + 3]; + + /*verify that current item has to be dealth with by this PU*/ + s_deal_with = sig_deal_with( + &(sig_subObj->inBuf[sig_subObj->inReadPos])); + + switch (s_deal_with) { + + case TRUE: + /* we have to manage this item */ + if (FALSE == sig_is_command( + &(sig_subObj->inBuf[sig_subObj->inReadPos]))) + { + /*no commands, item to deal with : switch to process state*/ + sig_subObj->procState = PICOSIG_PROCESS; + sig_subObj->retState = PICOSIG_COLLECT; + return PICODATA_PU_BUSY; /*data still to process or to feed*/ + + } else { + + /*we need to manage this item as a SIG command-item*/ + + switch (sig_subObj->inBuf[sig_subObj->inReadPos + 1]) { + + case PICODATA_ITEMINFO1_CMD_PLAY: + /*CMD recognized : consume the command */ + sig_subObj->inReadPos += numinb; + if (sig_subObj->inReadPos + >= sig_subObj->inWritePos) { + sig_subObj->inReadPos = 0; + sig_subObj->inWritePos = 0; + } + /*default next state setting*/ + sig_subObj->procState = + sig_subObj->retState = PICOSIG_COLLECT; + + /*--------- wav file play management --------------*/ + if (sig_subObj->sInSDFile != NULL) { + /*input wav file is already open : return*/ + return PICODATA_PU_BUSY; + } + /*get temp file name*/ + picoos_strlcpy( + (picoos_char*) s_temp_file_name, + (picoos_char*) &(sig_subObj->inBuf[sig_subObj->inReadPos + + 4]), + sig_subObj->inBuf[sig_subObj->inReadPos + + 3] + 1); + /*avoid input/output file name clashes*/ + if (sig_subObj->sOutSDFile != NULL) { + if (picoos_strncmp( + (picoos_char*) s_temp_file_name, + (picoos_char*) sig_subObj->sOutSDFileName, + picoos_strlen( + (picoos_char*) s_temp_file_name)) + == 0) { + PICODBG_WARN(("input and output files has the same name!\n")); + return PICODATA_PU_BUSY; + } + } + /*actual sampled data file open*/ + b_res = picoos_sdfOpenIn(this->common, + &(sig_subObj->sInSDFile), + s_temp_file_name, &sf, + &enc, &numSamples); + if (b_res != TRUE) { + PICODBG_DEBUG(("Error on opening file %s\n", s_temp_file_name)); + sig_subObj->sInSDFile = NULL; + sig_subObj->sInSDFileName[0] = '\0'; + return PICODATA_PU_BUSY; + } + /*input file handle is now valid : store filename*/ + picoos_strlcpy( + (picoos_char*) sig_subObj->sInSDFileName, + (picoos_char*) s_temp_file_name, + sig_subObj->inBuf[sig_subObj->inReadPos + + 3] + 1); + sig_subObj->sInSDFilePos = 0; + /*switch to state PLAY and return*/ + sig_subObj->procState = + sig_subObj->retState = PICOSIG_PLAY; + return PICODATA_PU_BUSY; + break; + + case PICODATA_ITEMINFO1_CMD_SAVE: + /*CMD recognized : consume the command */ + sig_subObj->inReadPos += numinb; + if (sig_subObj->inReadPos + >= sig_subObj->inWritePos) { + sig_subObj->inReadPos = 0; + sig_subObj->inWritePos = 0; + } + /*prepare return state*/ + sig_subObj->procState = PICOSIG_COLLECT; + sig_subObj->retState = PICOSIG_COLLECT; + /*check about output file*/ + if ((sig_subObj->sOutSDFile != NULL) + || (sig_subObj->outSwitch == 1)) { + /*output sig file is already active : return*/ + return PICODATA_PU_BUSY; + } + /*get temp file name*/ + picoos_strlcpy( + (picoos_char*) s_temp_file_name, + (picoos_char*) &(sig_subObj->inBuf[sig_subObj->inReadPos + + 4]), + sig_subObj->inBuf[sig_subObj->inReadPos + + 3] + 1); + /*check extension*/ + if (picoos_has_extension(s_temp_file_name, + PICODATA_PUTYPE_WAV_OUTPUT_EXTENSION) + == FALSE){ + /*extension unsupported : return*/ + return PICODATA_PU_BUSY; + } + /*avoid input/output file name clashes*/ + if (sig_subObj->sInSDFile != NULL) { + if (picoos_strncmp( + (picoos_char*) sig_subObj->sInSDFileName, + (picoos_char*) s_temp_file_name, + picoos_strlen( + (picoos_char*) sig_subObj->sInSDFileName)) + == 0) { + /*input and output files has the same name : do not allow opening for writing*/ + PICODBG_WARN(("input and output files has the same name!\n")); + return PICODATA_PU_BUSY; + } + } + /*try to open*/ + picoos_sdfOpenOut(this->common, + &(sig_subObj->sOutSDFile), + s_temp_file_name, + SAMPLE_FREQ_16KHZ, PICOOS_ENC_LIN); + if (sig_subObj->sOutSDFile == NULL) { + PICODBG_DEBUG(("Error on opening file %s\n", sig_subObj->sOutSDFileName)); + sig_subObj->outSwitch = 0; + sig_subObj->sOutSDFileName[0] = '\0'; + } else { + /*open OK*/ + sig_subObj->outSwitch = 1; + /*store output filename*/ + picoos_strlcpy( + (picoos_char*) sig_subObj->sOutSDFileName, + (picoos_char*) s_temp_file_name, + sig_subObj->inBuf[sig_subObj->inReadPos + 3] + 1); + } + return PICODATA_PU_BUSY; + break; + + case PICODATA_ITEMINFO1_CMD_UNSAVE: + /*CMD recognized : consume the command */ + sig_subObj->inReadPos += numinb; + if (sig_subObj->inReadPos + >= sig_subObj->inWritePos) { + sig_subObj->inReadPos = 0; + sig_subObj->inWritePos = 0; + } + /*prepare return state*/ + sig_subObj->procState = PICOSIG_COLLECT; + sig_subObj->retState = PICOSIG_COLLECT; + /*close the output file if any*/ + if ((sig_subObj->sOutSDFile == NULL) + || (sig_subObj->outSwitch == 0)) { + /*output sig file is not active : return*/ + PICODBG_DEBUG(("Error on requesting a binary samples file output closing : no file output handle exist\n")); + return PICODATA_PU_BUSY; + } + picoos_sdfCloseOut(this->common, + &(sig_subObj->sOutSDFile)); + sig_subObj->outSwitch = 0; + sig_subObj->sOutSDFile = NULL; + sig_subObj->sOutSDFileName[0] = '\0'; + return PICODATA_PU_BUSY; + break; + + case PICODATA_ITEMINFO1_CMD_PITCH: + case PICODATA_ITEMINFO1_CMD_VOLUME: + case PICODATA_ITEMINFO1_CMD_SPEAKER: + n_pos = 4; + picoos_read_mem_pi_uint16( + &(sig_subObj->inBuf[sig_subObj->inReadPos]), + &n_pos, &n_value); + b_res = FALSE; + switch (sig_subObj->inBuf[sig_subObj->inReadPos + 2]) { + case 'a' : + /*absloute modifier*/ + f_value = (picoos_single) n_value + / (picoos_single) 100.0f; + b_res = TRUE; + break; + case 'r' : + /*relative modifier*/ + f_value = (picoos_single) n_value + / (picoos_single) 1000.0f; + b_res = TRUE; + break; + default : + f_value = (picoos_single)0; /*avoid warnings*/ + break; + } + if (b_res) { + switch (sig_subObj->inBuf[sig_subObj->inReadPos + 1]) { + case PICODATA_ITEMINFO1_CMD_PITCH : + sig_subObj->pMod = f_value; + break; + case PICODATA_ITEMINFO1_CMD_VOLUME : + sig_subObj->vMod = f_value; + break; + case PICODATA_ITEMINFO1_CMD_SPEAKER : + sig_subObj->sMod = f_value; + sig_subObj->sig_inner.sMod_p + = sig_subObj->sMod; + /*call the function needed to initialize the speaker factor*/ + mel_2_lin_init( + &(sig_subObj->sig_inner)); + break; + default : + break; + } + } + + /*CMD recognized : consume the command */ + sig_subObj->inReadPos += numinb; + if (sig_subObj->inReadPos + >= sig_subObj->inWritePos) { + sig_subObj->inReadPos = 0; + sig_subObj->inWritePos = 0; + } + /*prepare proc state*/ + sig_subObj->procState = PICOSIG_COLLECT; + sig_subObj->retState = PICOSIG_COLLECT; + return PICODATA_PU_BUSY; + break; + default: + break; + }/*switch command type*/ + } /*end if is command*/ + break; + + case FALSE: + + /*we DO NOT have to deal with this item on this PU. + * Normally these are still alive boundary or flush items*/ + /*copy item from PU input to PU output buffer, + * i.e. make it ready to FEED*/ + s_result = picodata_copy_item( + &(sig_subObj->inBuf[sig_subObj->inReadPos]), + numinb, + &(sig_subObj->outBuf[sig_subObj->outWritePos]), + sig_subObj->outBufSize - sig_subObj->outWritePos, + &numoutb); + if (s_result != PICO_OK) { + /*item not prepared properly to be sent to next PU : + * do not change state and retry next time*/ + sig_subObj->procState = PICOSIG_SCHEDULE; + sig_subObj->retState = PICOSIG_COLLECT; + return PICODATA_PU_BUSY; /*data still to process or to feed*/ + } + + /*if end of sentence reset number of frames(only needed for debugging purposes)*/ + if ((sig_subObj->inBuf[sig_subObj->inReadPos] + == PICODATA_ITEM_BOUND) + && ((sig_subObj->inBuf[sig_subObj->inReadPos + 1] + == PICODATA_ITEMINFO1_BOUND_SEND) + || (sig_subObj->inBuf[sig_subObj->inReadPos + + 1] + == PICODATA_ITEMINFO1_BOUND_TERM))) { + PICODBG_INFO(("End of sentence - Processed frames : %d", + sig_subObj->nNumFrame)); + sig_subObj->nNumFrame = 0; + } + + /*item processed and put in oputput buffer : consume the item*/ + sig_subObj->inReadPos += numinb; + sig_subObj->outWritePos += numoutb; + if (sig_subObj->inReadPos >= sig_subObj->inWritePos) { + /* inBuf exhausted */ + sig_subObj->inReadPos = 0; + sig_subObj->inWritePos = 0; + sig_subObj->needMoreInput = FALSE; + } + sig_subObj->procState = PICOSIG_FEED; + sig_subObj->retState = PICOSIG_COLLECT; + return PICODATA_PU_BUSY; /*data still to process or to feed*/ + break; + + default: + break; + }/*end switch s_deal_with*/ + + break; /*end case sig_schedule*/ + + case PICOSIG_PROCESS: + /* *************** item processing ***********************************/ + numinb = PICODATA_ITEM_HEADSIZE + + sig_subObj->inBuf[sig_subObj->inReadPos + 3]; + + /*Process a full item*/ + s_result = sigProcess(this, sig_subObj->inReadPos, numinb, + sig_subObj->outWritePos, &numoutb); + + if (s_result == PICO_OK) { + sig_subObj->inReadPos += numinb; + if (sig_subObj->inReadPos >= sig_subObj->inWritePos) { + sig_subObj->inReadPos = 0; + sig_subObj->inWritePos = 0; + sig_subObj->needMoreInput = FALSE; + } + sig_subObj->outWritePos += numoutb; + sig_subObj->procState = PICOSIG_FEED; + sig_subObj->retState = PICOSIG_COLLECT; + PICODBG_DEBUG(("picosig.sigStep -- leaving PICO_PROC, inReadPos = %i, outWritePos = %i",sig_subObj->inReadPos, sig_subObj->outWritePos)); + return PICODATA_PU_BUSY; /*data to feed*/ + } + return PICODATA_PU_BUSY; /*data still to process : remain in PROCESS STATE*/ + break; + + case PICOSIG_PLAY: + + /*management of wav file play*/ + s_data = (picoos_int16 *) &(sig_subObj->outBuf[sig_subObj->outWritePos + 4]); + hop_p_half = sig_subObj->sig_inner.hop_p / 2; + /*read directly into PU output buffer*/ + n_samp = hop_p_half; + b_res = picoos_sdfGetSamples(sig_subObj->sInSDFile, + sig_subObj->sInSDFilePos, &n_samp, s_data); + sig_subObj->sInSDFilePos += n_samp; + + if ((FALSE == b_res) || (0 == n_samp)) { + /*file play is complete or file read error*/ + picoos_sdfCloseIn(this->common, &(sig_subObj->sInSDFile)); + sig_subObj->sInSDFile = NULL; + sig_subObj->sInSDFileName[0] = '\0'; + sig_subObj->procState = PICOSIG_COLLECT; + sig_subObj->retState = PICOSIG_COLLECT; + return PICODATA_PU_BUSY; /*check if data in input buffer*/ + } + /*-----------------------------------*/ + /*Volume control of wav file playback*/ + /* (code borrowed from sigProcess)*/ + /*Volume mod and clipping control */ + /* directly into PU output buffer*/ + /*-----------------------------------*/ + sf_mlt = (picoos_int32) ((sig_subObj->vMod) * 16.0f); + s_t1 = &(s_data[0]); + + for (n_i = 0; n_i < n_samp; n_i++) { + if (*s_t1 != 0) { + sf_data = (picoos_int32) (*s_t1) * sf_mlt; + sf_data >>= 4; + if (sf_data > PICOSIG_MAXAMP) { + sf_data = PICOSIG_MAXAMP; + } else if (sf_data < PICOSIG_MINAMP) { + sf_data = PICOSIG_MINAMP; + } + *s_t1 = (picoos_int16) (sf_data); + } + s_t1++; + } + /*Add header info*/ + sig_subObj->outBuf[sig_subObj->outWritePos] + = (picoos_uint8) PICODATA_ITEM_FRAME; + sig_subObj->outBuf[sig_subObj->outWritePos + 1] + = (picoos_uint8) n_samp; + sig_subObj->outBuf[sig_subObj->outWritePos + 2] + = (picoos_uint8) (sig_subObj->nNumFrame % (hop_p_half)); /*number of frame % 64*/ + sig_subObj->outBuf[sig_subObj->outWritePos + 3] + = (picoos_uint8) n_samp * 2; + /*Item content*/ + sig_subObj->outWritePos += (n_samp * sizeof(picoos_int16)) + 4; /*including header*/ + sig_subObj->procState = PICOSIG_FEED; + sig_subObj->retState = PICOSIG_PLAY; + break; + + case PICOSIG_FEED: + /* ************** item output/feeding ***********************************/ + switch (sig_subObj->outSwitch) { + case 0: + /*feeding items to PU output buffer*/ + s_result = picodata_cbPutItem(this->cbOut, + &(sig_subObj->outBuf[sig_subObj->outReadPos]), + sig_subObj->outWritePos - sig_subObj->outReadPos, + &numoutb); + break; + case 1: + /*feeding items to file*/ + if (sig_subObj->outBuf[sig_subObj->outReadPos] + == PICODATA_ITEM_FRAME) { + if ((sig_subObj->sOutSDFile) != NULL) { + n_start = (picoos_uint32) (sig_subObj->outReadPos) + + PICODATA_ITEM_HEADSIZE; + n_bytes = (picoos_uint32) sig_subObj->outBuf[(sig_subObj->outReadPos) + + PICODATA_ITEMIND_LEN]; + n_fram = (picoos_uint32) sig_subObj->outBuf[(sig_subObj->outReadPos) + + PICODATA_ITEMIND_INFO2]; + if (picoos_sdfPutSamples( + sig_subObj->sOutSDFile, + n_bytes / 2, + (picoos_int16*) &(sig_subObj->outBuf[n_start]))) { + PICODBG_DEBUG(("Nframe:%d - Nbytes %d\n", n_fram, n_bytes)); + numoutb = n_bytes + 4; + s_result = PICO_OK; + /* also feed item to next PU */ + s_result = picodata_cbPutItem( + this->cbOut, + &(sig_subObj->outBuf[sig_subObj->outReadPos]), + sig_subObj->outWritePos + - sig_subObj->outReadPos, + &numoutb); + } else { + /*write error : close file + cleanup handles*/ + if (sig_subObj->sOutSDFile != NULL) { + picoos_sdfCloseOut(this->common, &(sig_subObj->sOutSDFile)); + sig_subObj->sOutSDFile = NULL; + } + sig_subObj->sOutSDFileName[0] = '\0'; + sig_subObj->outSwitch = 0; + PICODBG_DEBUG(("Error in writing :%d bytes to output file %s\n", numoutb, &(sig_subObj->sOutSDFileName[0]))); + s_result = PICO_ERR_OTHER; + } + } + } else { + /*continue to feed following PU with items != FRAME */ + s_result = picodata_cbPutItem( + this->cbOut, + &(sig_subObj->outBuf[sig_subObj->outReadPos]), + sig_subObj->outWritePos - sig_subObj->outReadPos, + &numoutb); + } + break; + default: + s_result = PICO_ERR_OTHER; + break; + } + PICODBG_DEBUG(("picosig.sigStep -- put item, status: %d",s_result)); + + if (PICO_OK == s_result) { + + sig_subObj->outReadPos += numoutb; + *numBytesOutput = numoutb; + /*-------------------------*/ + /*reset the output pointers*/ + /*-------------------------*/ + if (sig_subObj->outReadPos >= sig_subObj->outWritePos) { + sig_subObj->outReadPos = 0; + sig_subObj->outWritePos = 0; + sig_subObj->procState = sig_subObj->retState; + } + return PICODATA_PU_BUSY; + + } else if (PICO_EXC_BUF_OVERFLOW == s_result) { + + PICODBG_DEBUG(("picosig.sigStep ** feeding, overflow, PICODATA_PU_OUT_FULL")); + return PICODATA_PU_OUT_FULL; + + } else if ((PICO_EXC_BUF_UNDERFLOW == s_result) + || (PICO_ERR_OTHER == s_result)) { + + PICODBG_DEBUG(("picosig.sigStep ** feeding problem, discarding item")); + sig_subObj->outReadPos = 0; + sig_subObj->outWritePos = 0; + sig_subObj->procState = sig_subObj->retState; + return PICODATA_PU_ERROR; + + } + break; + default: + /*NOT feeding items*/ + s_result = PICO_EXC_BUF_IGNORE; + break; + }/*end switch*/ + return PICODATA_PU_BUSY; /*check if there is more data to process after feeding*/ + + }/*end while*/ + return PICODATA_PU_IDLE; +}/*sigStep*/ + +#ifdef __cplusplus +} +#endif + +/* Picosig.c end */ diff --git a/pico/lib/picosig.h b/pico/lib/picosig.h new file mode 100644 index 0000000..3e29e8f --- /dev/null +++ b/pico/lib/picosig.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picosig.h + * + * Signal Generation PU - Header file + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ +/** + * @addtogroup picosig + * + * Pico Signal Generation module \n + * + * Pico Sig is the PU that makes the parametric representation produce a speech signal. + * The PU receives parametric vectors and translates them into signal vectors. + * Most of the processing is based on this 1 to 1 relationship between input and output vectors. + * + * NOTE : "picosig" includes logically "picosig2" module, that is the DSP implementation of the signal generation. +*/ + +#ifndef PICOSIG_H_ +#define PICOSIG_H_ + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +/* ******************************************************************************* + * items related to the generic interface + ********************************************************************************/ +picodata_ProcessingUnit picosig_newSigUnit( + picoos_MemoryManager mm, + picoos_Common common, + picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, + picorsrc_Voice voice); + +#ifdef __cplusplus +} +#endif + +#endif /*PICOSIG_H_*/ diff --git a/pico/lib/picosig2.c b/pico/lib/picosig2.c new file mode 100644 index 0000000..b698b4f --- /dev/null +++ b/pico/lib/picosig2.c @@ -0,0 +1,4105 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picosig2.c + * + * Signal Generation PU - Internal functions - Implementation + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ +#include "picoos.h" +#include "picodsp.h" +#include "picosig2.h" +#include "picofftsg.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif +/*--------------------------------------------------------------------------- + * INTERNAL FUNCTIONS DECLARATION + *---------------------------------------------------------------------------*/ +static void gen_hann2(sig_innerobj_t *sig_inObj); +static void get_simple_excitation(sig_innerobj_t *sig_inObj, + picoos_int16 *nextPeak); +static void enh_wind_init(sig_innerobj_t *sig_inObj); +static void init_rand(sig_innerobj_t *sig_inObj); +static void get_trig(picoos_int32 ang, picoos_int32 *table, picoos_int32 *cs, + picoos_int32 *sn); + +/*--------------------------------------------------------------------------- + * PICO SYSTEM FUNCTIONS + *---------------------------------------------------------------------------*/ +/** + * allocation of DSP memory for SIG PU + * @param mm : memory manager + * @param sig_inObj : sig PU internal object of the sub-object + * @return PICO_OK : allocation successful + * @return PICO_ERR_OTHER : allocation NOT successful + * @callgraph + * @callergraph + */ +pico_status_t sigAllocate(picoos_MemoryManager mm, sig_innerobj_t *sig_inObj) +{ + picoos_int16 *data_i; + picoos_int32 *d32; + picoos_int32 nCount; + + sig_inObj->int_vec22 = + sig_inObj->int_vec23 = + sig_inObj->int_vec24 = + sig_inObj->int_vec25 = + sig_inObj->int_vec26 = + sig_inObj->int_vec28 = + sig_inObj->int_vec29 = + sig_inObj->int_vec30 = + sig_inObj->int_vec31 = + sig_inObj->int_vec32 = + sig_inObj->int_vec33 = + sig_inObj->int_vec34 = + sig_inObj->int_vec35 = + sig_inObj->int_vec36 = + sig_inObj->int_vec37 = + sig_inObj->int_vec38 = + sig_inObj->int_vec39 = + sig_inObj->int_vec40 = NULL; + + sig_inObj->sig_vec1 = NULL; + + sig_inObj->idx_vect1 = sig_inObj->idx_vect2 = sig_inObj->idx_vect4 = NULL; + sig_inObj->idx_vect5 = sig_inObj->idx_vect6 = sig_inObj->idx_vect7 = + sig_inObj->idx_vect8 = sig_inObj->idx_vect9 = NULL; + sig_inObj->ivalue17 = sig_inObj->ivalue18 = 0; + + /*----------------------------------------------------------------- + * Memory allocations + * NOTE : it would be far better to do a single allocation + * and to do pointer initialization inside this routine + * ------------------------------------------------------------------*/ + data_i = (picoos_int16 *) picoos_allocate(mm, sizeof(picoos_int16) + * PICODSP_FFTSIZE); + if (NULL == data_i) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->idx_vect1 = data_i; + + data_i = (picoos_int16 *) picoos_allocate(mm, sizeof(picoos_int16) + * PICODSP_HFFTSIZE_P1); + if (NULL == data_i) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->idx_vect2 = data_i; + + data_i = (picoos_int16 *) picoos_allocate(mm, sizeof(picoos_int16) + * PICODSP_FFTSIZE); + if (NULL == data_i) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->idx_vect4 = data_i; + + data_i = (picoos_int16 *) picoos_allocate(mm, sizeof(picoos_int16) + * PICODSP_FFTSIZE); + if (NULL == data_i) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->idx_vect5 = data_i; + + data_i = (picoos_int16 *) picoos_allocate(mm, sizeof(picoos_int16) + * PICODSP_FFTSIZE); + if (NULL == data_i) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->idx_vect6 = data_i; + + data_i = (picoos_int16 *) picoos_allocate(mm, sizeof(picoos_int16) + * PICODSP_HFFTSIZE_P1); + if (NULL == data_i) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->idx_vect7 = data_i; + + data_i = (picoos_int16 *) picoos_allocate(mm, sizeof(picoos_int16) + * PICODSP_MAX_EX); + if (NULL == data_i) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->idx_vect8 = data_i; + + data_i = (picoos_int16 *) picoos_allocate(mm, sizeof(picoos_int16) + * PICODSP_MAX_EX); + if (data_i == NULL) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->idx_vect9 = data_i; + + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_FFTSIZE); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec22 = d32; + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_FFTSIZE); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec23 = d32; + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_FFTSIZE); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec24 = d32; + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_FFTSIZE); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec25 = d32; + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_FFTSIZE * 2); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec26 = d32; + + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_FFTSIZE); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec28 = d32; + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_FFTSIZE); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec29 = d32; + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_FFTSIZE); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec38 = d32; + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_FFTSIZE); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec30 = d32; + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_FFTSIZE); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec31 = d32; + + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_FFTSIZE); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec32 = d32; + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_FFTSIZE); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec33 = d32; + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_N_RAND_TABLE); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec34 = d32; + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_N_RAND_TABLE); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec35 = d32; + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_N_RAND_TABLE); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec36 = d32; + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_N_RAND_TABLE); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec37 = d32; + + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_HFFTSIZE_P1); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec39 = d32; + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) * (1 + + PICODSP_COS_TABLE_LEN)); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec40 = d32; + + for (nCount = 0; nCount < CEPST_BUFF_SIZE; nCount++) { + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) * (PICODSP_CEPORDER)); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec41[nCount] = d32; + } + + for (nCount = 0; nCount < PHASE_BUFF_SIZE; nCount++) { + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) * (PICODSP_PHASEORDER)); + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->int_vec42[nCount] = d32; + } + + d32 = (picoos_int32 *) picoos_allocate(mm, sizeof(picoos_int32) + * PICODSP_FFTSIZE * 2); /* - fixed point */ + if (NULL == d32) { + sigDeallocate(mm, sig_inObj); + return PICO_ERR_OTHER; + } + sig_inObj->sig_vec1 = d32; + + return PICO_OK; +}/*sigAllocate*/ + +/** + * frees DSP memory for SIG PU + * @param mm : memory manager + * @param sig_inObj : sig PU internal object of the sub-object + * @return void + * @callgraph + * @callergraph + */ +void sigDeallocate(picoos_MemoryManager mm, sig_innerobj_t *sig_inObj) +{ + picoos_int32 nCount; + /*----------------------------------------------------------------- + * Memory de-allocations + * ------------------------------------------------------------------*/ + if (NULL != sig_inObj->idx_vect1) + picoos_deallocate(mm, (void *) &(sig_inObj->idx_vect1)); + if (NULL != sig_inObj->idx_vect2) + picoos_deallocate(mm, (void *) &(sig_inObj->idx_vect2)); + if (NULL != sig_inObj->idx_vect4) + picoos_deallocate(mm, (void *) &(sig_inObj->idx_vect4)); + if (NULL != sig_inObj->idx_vect5) + picoos_deallocate(mm, (void *) &(sig_inObj->idx_vect5)); + if (NULL != sig_inObj->idx_vect6) + picoos_deallocate(mm, (void *) &(sig_inObj->idx_vect6)); + if (NULL != sig_inObj->idx_vect7) + picoos_deallocate(mm, (void *) &(sig_inObj->idx_vect7)); + if (NULL != sig_inObj->idx_vect8) + picoos_deallocate(mm, (void *) &(sig_inObj->idx_vect8)); + if (NULL != sig_inObj->idx_vect9) + picoos_deallocate(mm, (void *) &(sig_inObj->idx_vect9)); + + if (NULL != sig_inObj->int_vec22) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec22)); + if (NULL != sig_inObj->int_vec23) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec23)); + if (NULL != sig_inObj->int_vec24) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec24)); + if (NULL != sig_inObj->int_vec25) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec25)); + if (NULL != sig_inObj->int_vec26) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec26)); + if (NULL != sig_inObj->int_vec28) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec28)); + if (NULL != sig_inObj->int_vec29) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec29)); + if (NULL != sig_inObj->int_vec38) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec38)); + if (NULL != sig_inObj->int_vec30) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec30)); + if (NULL != sig_inObj->int_vec31) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec31)); + if (NULL != sig_inObj->int_vec32) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec32)); + if (NULL != sig_inObj->int_vec33) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec33)); + if (NULL != sig_inObj->int_vec34) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec34)); + if (NULL != sig_inObj->int_vec35) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec35)); + if (NULL != sig_inObj->int_vec36) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec36)); + if (NULL != sig_inObj->int_vec37) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec37)); + if (NULL != sig_inObj->int_vec39) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec39)); + if (NULL != sig_inObj->int_vec40) + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec40)); + + for (nCount = 0; nCount < CEPST_BUFF_SIZE; nCount++) { + if (NULL != sig_inObj->int_vec41[nCount]) { + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec41[nCount])); + } + } + + for (nCount = 0; nCount < PHASE_BUFF_SIZE; nCount++) { + if (NULL != sig_inObj->int_vec42[nCount]) { + picoos_deallocate(mm, (void *) &(sig_inObj->int_vec42[nCount])); + } + } + + if (NULL != sig_inObj->sig_vec1) { + picoos_deallocate(mm, (void *) &(sig_inObj->sig_vec1)); + } +}/*sigDeAllocate*/ + +/** + * initializes all memory neededed by DSP at instance creation time + * @param sig_inObj : sig PU internal object of the sub-object + * @return void + * @callgraph + * @callergraph + */ +void sigDspInitialize(sig_innerobj_t *sig_inObj, picoos_int32 resetMode) +{ + picoos_int32 i, j; + picoos_int32 *pnt; + + if (resetMode == PICO_RESET_SOFT) { + /*minimal initialization when receiving a soft reset */ + return; + } + /*----------------------------------------------------------------- + * Initialization + * ------------------------------------------------------------------*/ + sig_inObj->warp_p = PICODSP_FREQ_WARP_FACT; + sig_inObj->VCutoff_p = PICODSP_V_CUTOFF_FREQ; /*voicing cut off frequency in Hz (will be modeled in the future)*/ + sig_inObj->UVCutoff_p = PICODSP_UV_CUTOFF_FREQ;/*unvoiced frames only (periodize lowest components to mask bad voicing transitions)*/ + sig_inObj->Fs_p = PICODSP_SAMP_FREQ; /*Sampling freq*/ + + sig_inObj->m1_p = PICODSP_CEPORDER; + sig_inObj->m2_p = PICODSP_FFTSIZE; /*also initializes windowLen*/ + sig_inObj->framesz_p = PICODSP_DISPLACE; /*1/4th of the frame size = displacement*/ + sig_inObj->hfftsize_p = PICODSP_H_FFTSIZE; /*half of the FFT size*/ + sig_inObj->voxbnd_p = (picoos_int32) ((picoos_single) sig_inObj->hfftsize_p + / ((picoos_single) sig_inObj->Fs_p / (picoos_single) 2) + * (picoos_single) sig_inObj->VCutoff_p); + sig_inObj->voxbnd2_p + = (picoos_int32) ((picoos_single) sig_inObj->hfftsize_p + / ((picoos_single) sig_inObj->Fs_p / (picoos_single) 2) + * (picoos_single) sig_inObj->UVCutoff_p); + sig_inObj->hop_p = sig_inObj->framesz_p; + sig_inObj->nextPeak_p = (((int) (PICODSP_FFTSIZE)) + / ((int) PICODSP_DISPLACE) - 1) * sig_inObj->hop_p; + sig_inObj->phId_p = 0; /*phonetic id*/ + sig_inObj->E_p = (picoos_single) 0.0f; + sig_inObj->F0_p = (picoos_single) 0.0f; + sig_inObj->voiced_p = 0; + sig_inObj->nV = sig_inObj->nU = 0; + sig_inObj->sMod_p = (picoos_single) 1.0f; + + /*cleanup vectors*/ + for (i = 0; i < 2 * PICODSP_FFTSIZE; i++) { + sig_inObj->sig_vec1[i] = 0; + sig_inObj->int_vec26[i] = 0; /*wav buff cleanup */ + } + + for (i = 0; i < PICODSP_FFTSIZE; i++) { + sig_inObj->idx_vect1[i] = sig_inObj->idx_vect4[i] + = sig_inObj->idx_vect5[i] = sig_inObj->idx_vect6[i] = 0; + sig_inObj->int_vec32[i] = sig_inObj->int_vec33[i] = 0; + } + + for (i = 0; i < PICODSP_HFFTSIZE_P1; i++) { + sig_inObj->idx_vect2[i] = (picoos_int16) 0; + } + + for (i = 0; i < CEPST_BUFF_SIZE; i++) { + sig_inObj->F0Buff[i]=0; + sig_inObj->PhIdBuff[i]=0; + sig_inObj->VoicingBuff[i]=0; + sig_inObj->FuVBuff[i]=0; + if (NULL != sig_inObj->CepBuff[i]) { + pnt = sig_inObj->CepBuff[i]; + for (j = 0; j < PICODSP_CEPORDER; j++) { + pnt[j] = 0; + } + } + } + + for (i = 0; i < PHASE_BUFF_SIZE; i++) { + if (NULL != sig_inObj->int_vec42[i]) { + pnt = sig_inObj->int_vec42[i]; + for (j = 0; j < PICODSP_PHASEORDER; j++) { + pnt[j] = 0; + } + } + } + sig_inObj->n_available=0; + /*--------------------------------------------- + Init formant enhancement window + hanning window, + Post Filter Hermite's interpolator Matrix + Mel-2-Lin lookup tables + ---------------------------------------------*/ + enh_wind_init(sig_inObj); /*creates the formant enhancement window*/ + init_rand(sig_inObj); + gen_hann2(sig_inObj); + mel_2_lin_init(sig_inObj); + +}/*sigDspInitialize*/ + +/*------------------------------------------------------------------------------- + PROCESSING FUNCTIONS : CALLED WITHIN sigStep (cfr. picosig.c) + --------------------------------------------------------------------------------*/ +/** + * convert from mel scale to linear scale + * @param sig_inObj : sig PU internal object of the sub-object + * @param scmeanMGC : mean value of the MGC + * @return void + * @callgraph + * @callergraph + * @remarks translated from matlab code to c-code + * Input + * - c1 : input mfcc vector (ceporder=m1, real) + * - m1 : input order + * - A,B,D : lookup tables + * - m2 : output order + * - Xr,Xi (m2=FFT size, real) temporary arrays for FFT + * - WNr,WNi (m2=FFT size, real) cos and sin precalculated tables + * Output + * - Xr (m2=FFT size, real) linear cepstral vector + */ +void mel_2_lin_lookup(sig_innerobj_t *sig_inObj, picoos_uint32 scmeanMGC) +{ + /*Local vars*/ + picoos_int16 nI, k; + picoos_int32 delta, term1, term2; + + /*Local vars to be linked with sig data object*/ + picoos_int32 *c1, *XXr; + picoos_single K1; + picoos_int32 *D, K2, shift; + picoos_int16 m1, *A, m2, m4, voiced, i; + + /*Link local variables with sig data object*/ + c1 = sig_inObj->wcep_pI; + m1 = sig_inObj->m1_p; + m2 = PICODSP_FFTSIZE; + m4 = m2 >> 1; + + A = sig_inObj->A_p; + D = sig_inObj->d_p; + + XXr = sig_inObj->wcep_pI; + voiced = sig_inObj->voiced_p; + + shift = 27 - scmeanMGC; + K2 = 1 << shift; + K1 = (picoos_single) PICODSP_START_FLOAT_NORM * K2; + XXr[0] = (picoos_int32) ((picoos_single) c1[0] * K1); + for (nI = 1; nI < m1; nI++) { + if (c1[nI] >= 0) + XXr[nI] = c1[nI] << shift; + else + XXr[nI] = -(-c1[nI] << shift); + } + i = sizeof(picoos_int32) * (PICODSP_FFTSIZE - m1); + picoos_mem_set(XXr + m1, 0, i); + dfct_nmf(m4, XXr); /* DFCT directly in fixed point */ + + /* ***************************************************************************************** + Linear frequency scale envelope through interpolation. + Two additions and one multiplication per entry. + + Optimization of linear interpolation algorithm + - Start from 1 and stop at PICODSP_H_FFTSIZE-1 because 0 and PICODSP_H_FFTSIZE are invariant points + - B[k]=A[k]+1 except for 0 and PICODSP_H_FFTSIZE + - get rid of extra -1 operation by adapting the table A[] + + *******************************************************************************************/ + for (nI = 1; nI < PICODSP_H_FFTSIZE; nI++) { + k = A[nI]; + term2 = XXr[k]; + term1 = XXr[k + 1]; + delta = term1 - term2; + XXr[nI] = term2 + (((picoos_single)D[nI] * (picoos_single)delta) / 32); /* ok because nI<=A[nI] <=B[nI] */ + } +}/*mel_2_lin_lookup*/ + +/** + * calculate phase + * @remarks voiced phase taken from phase codebook and smoothed, + * @remarks unvoiced phase - random + * @param sig_inObj : sig PU internal object of the sub-object + * @return void + * @callgraph + * @callergraph + */ +void phase_spec2(sig_innerobj_t *sig_inObj) +{ + picoos_int16 nI, iRand, firstUV; + picoos_int32 *tmp1, *tmp2; + picoos_int16 VOXBND_M1; + picoos_int32 *spect, *ang; + picoos_int16 voiced, m2; + picoos_int32 *co, *so, *c, *s, voxbnd, voxbnd2; + picoos_int16 i,j, k, n_comp; + picoos_int16 *Pvoxbnd; + picoos_int32 *phs_p2, *phs_p1, *phs_n1, *phs_n2; + picoos_int32 *phs; + + /*Link local variables to sig data object*/ + spect = sig_inObj->wcep_pI; /* spect_p;*/ + /* current spect scale : times PICODSP_FIX_SCALE1 */ + ang = sig_inObj->ang_p; + voxbnd = (picoos_int32) (sig_inObj->voxbnd_p * sig_inObj->voicing); + voxbnd2 = sig_inObj->voxbnd2_p; + voiced = sig_inObj->voiced_p; + m2 = sig_inObj->m2_p; + VOXBND_M1 = voxbnd - 1; + firstUV = 1; + + /*code starts here*/ + if (voiced == 1) { + firstUV = voxbnd; + Pvoxbnd = sig_inObj->VoxBndBuff; + n_comp = Pvoxbnd[2]; + phs_p2 = sig_inObj->PhsBuff[0]; + phs_p1 = sig_inObj->PhsBuff[1]; + phs = sig_inObj->PhsBuff[2]; + phs_n1 = sig_inObj->PhsBuff[3]; + phs_n2 = sig_inObj->PhsBuff[4]; + + /* find and smooth components which have full context */ + j = n_comp; + for (i=0; i<5; i++) { + if (Pvoxbnd[i]=0)?(*tmp2)>>PICODSP_SHIFT_FACT4:-((-(*tmp2))>>PICODSP_SHIFT_FACT4);tmp2++); + *tmp2 = (*tmp2 >= 0) ? (*tmp2) >> PICODSP_SHIFT_FACT4 : -((-(*tmp2)) + >> PICODSP_SHIFT_FACT4); /*ang[voxbnd-1]/=2;*/ + } + + /* now for the unvoiced part */ + iRand = sig_inObj->iRand; + c = sig_inObj->randCosTbl + iRand; + s = sig_inObj->randSinTbl + iRand; + co = sig_inObj->outCosTbl + firstUV; + so = sig_inObj->outSinTbl + firstUV; + for (nI = firstUV; nI < PICODSP_HFFTSIZE_P1 - 1; nI++) { + *co++ = *c++; + *so++ = *s++; + } + *co = 1; + *so = 0; + sig_inObj->iRand += (PICODSP_HFFTSIZE_P1 - firstUV); + if (sig_inObj->iRand > PICODSP_N_RAND_TABLE - PICODSP_HFFTSIZE_P1) + sig_inObj->iRand = 1 + sig_inObj->iRand + PICODSP_HFFTSIZE_P1 + - PICODSP_N_RAND_TABLE; +}/*phase_spec2*/ + +/** + * Prepare Envelope spectrum for inverse FFT + * @param sig_inObj : sig PU internal object of the sub-object + * @return void + * @remarks make phase bilateral -->> angh (FFT size, real) + * @remarks combine in complex input vector for IFFT F = e**(spet/2+j*ang) + * @remarks Compute energy -->> E (scalar, real) + * @callgraph + * @callergraph + * Input + * - spect (FFT size, real) + * - ang (half FFT size -1, real) + * - m2 fftsize + * - WNr,WNi (FFT size, real) the tabulated sine and cosine values + * - brev (FFT size, real) the tabulated bit reversal indexes + * Output + * - Fr, Fi (FFT size, complex) the envelope spectrum + * - E (scalar, real) the energy + */ +void env_spec(sig_innerobj_t *sig_inObj) +{ + + picoos_int16 nI; + picoos_int32 fcX, fsX, fExp, voxbnd; + picoos_int32 *spect, *ang, *ctbl; + picoos_int16 voiced, prev_voiced; + picoos_int32 *co, *so; + picoos_int32 *Fr, *Fi; + picoos_single mult; + + /*Link local variables to sig object*/ + spect = sig_inObj->wcep_pI; /*spect_p*/ + /* current spect scale : times PICODSP_FIX_SCALE1 */ + ang = sig_inObj->ang_p; + /* current spect scale : PICODSP_M_PI = PICODSP_FIX_SCALE2 */ + Fr = sig_inObj->F2r_p; + Fi = sig_inObj->F2i_p; + voiced = sig_inObj->voiced_p; + prev_voiced = sig_inObj->prevVoiced_p; + voxbnd = (picoos_int32) (sig_inObj->voxbnd_p * sig_inObj->voicing); + ctbl = sig_inObj->cos_table; + /* ctbl scale : times 4096 */ + mult = PICODSP_ENVSPEC_K1 / PICODSP_FIX_SCALE1; + + /*remove dc from real part*/ + if (sig_inObj->F0_p > 120) { + spect[0] = spect[1] = 0; + spect[2] /= PICODSP_ENVSPEC_K2; + } else { + spect[0] = 0; + } + + /* if using rand table, use sin and cos tables as well */ + if (voiced || (prev_voiced)) { + /*Envelope becomes a complex exponential : F=exp(.5*spect + j*angh);*/ + for (nI = 0; nI < voxbnd; nI++) { + get_trig(ang[nI], ctbl, &fcX, &fsX); + fExp = (picoos_int32) EXP((double)spect[nI]*mult); + Fr[nI] = fExp * fcX; + Fi[nI] = fExp * fsX; + } + /* ao=sig_inObj->ang_p+(picoos_int32)voxbnd; */ + co = sig_inObj->outCosTbl + voxbnd; + so = sig_inObj->outSinTbl + voxbnd; + + for (nI = voxbnd; nI < PICODSP_HFFTSIZE_P1; nI++) { + fcX = *co++; + fsX = *so++; + fExp = (picoos_int32) EXP((double)spect[nI]*mult); + Fr[nI] = fExp * fcX; + Fi[nI] = fExp * fsX; + } + } else { + /*ao=sig_inObj->ang_p+1;*/ + co = sig_inObj->outCosTbl + 1; + so = sig_inObj->outSinTbl + 1; + for (nI = 1; nI < PICODSP_HFFTSIZE_P1; nI++) { + fcX = *co++; + fsX = *so++; + fExp = (picoos_int32) EXP((double)spect[nI]*mult); + + Fr[nI] = fExp * fcX; + Fi[nI] = fExp * fsX; + } + } + +}/*env_spec*/ + +/** + * Calculates the impulse response of the comlpex spectrum through inverse rFFT + * @param sig_inObj : sig PU internal object of the sub-object + * @return void + * @remarks Imp corresponds with the real part of the FFT + * @callgraph + * @callergraph + * Input + * - Fr, Fi (FFT size, real & imaginary) the complex envelope spectrum (only first half of spectrum) + * Output + * - Imp: impulse response (length: m2) + * - E (scalar, real) RMS value + */ +void impulse_response(sig_innerobj_t *sig_inObj) +{ + /*Define local variables*/ + picoos_single f; + picoos_int16 nI, nn, m2, m4, voiced; + picoos_single *E; + picoos_int32 *norm_window; /* - fixed point */ + picoos_int32 *fr, *Fr, *Fi, *t1, ff; /* - fixed point */ + + /*Link local variables with sig object*/ + m2 = sig_inObj->m2_p; + m4 = m2 >> 1; + Fr = sig_inObj->F2r_p; + Fi = sig_inObj->F2i_p; + norm_window = sig_inObj->norm_window_p; + E = &(sig_inObj->E_p); /*as pointer: value will be modified*/ + voiced = sig_inObj->voiced_p; + fr = sig_inObj->imp_p; + + /*Inverse FFT*/ + for (nI = 0, nn = 0; nI < m4; nI++, nn += 2) { + fr[nn] = Fr[nI]; /* - fixed point */ + } + + fr[1] = (picoos_int32) (Fr[m4]); + for (nI = 1, nn = 3; nI < m4; nI++, nn += 2) { + fr[nn] = -Fi[nI]; /* - fixed point */ + } + + rdft(m2, -1, fr); + /*window, normalize and differentiate*/ + *E = norm_result(m2, fr, norm_window); + + if (*E > 0) { + f = *E * PICODSP_FIXRESP_NORM; + } else { + f = 20; /*PICODSP_FIXRESP_NORM*/ + } + ff = (picoos_int32) f; + if (ff < 1) + ff = 1; + /*normalize impulse response*/ + t1 = fr;FAST_DEVICE(PICODSP_FFTSIZE,*(t1++) /= ff;); /* - fixed point */ + +} /* impulse_response */ + +/** + * time domain pitch synchronous overlap add over two frames (when no voicing transition) + * @param sig_inObj : sig PU internal object of the sub-object + * @return void + * @remarks Special treatment at voicing boundaries + * @remarks Introduced to get rid of time-domain aliasing (and additional speed up) + * @callgraph + * @callergraph + */ +void td_psola2(sig_innerobj_t *sig_inObj) +{ + picoos_int16 nI; + picoos_int16 hop, m2, *nextPeak, voiced; + picoos_int32 *t1, *t2; + picoos_int16 cnt; + picoos_int32 *fr, *v1, ff, f; + picoos_int16 a, i; + picoos_int32 *window; + picoos_int16 s = (picoos_int16) 1; + window = sig_inObj->window_p; + + /*Link local variables with sig object*/ + hop = sig_inObj->hop_p; + m2 = sig_inObj->m2_p; + nextPeak = &(sig_inObj->nextPeak_p); + voiced = sig_inObj->voiced_p; + fr = sig_inObj->imp_p; + /*toggle the pointers and initialize signal vector */ + v1 = sig_inObj->sig_vec1; + + t1 = v1; + FAST_DEVICE(PICODSP_FFTSIZE-PICODSP_DISPLACE,*(t1++)=0;); + t1 = &(v1[PICODSP_FFTSIZE - PICODSP_DISPLACE]); + t2 = &(v1[PICODSP_FFTSIZE]); + FAST_DEVICE(PICODSP_FFTSIZE, *(t1++)=*(t2++);); + t1 = &(v1[2 * PICODSP_FFTSIZE - PICODSP_DISPLACE]);FAST_DEVICE(PICODSP_DISPLACE,*(t1++)=0;); + /*calculate excitation points*/ + get_simple_excitation(sig_inObj, nextPeak); + + /*TD-PSOLA based on excitation vector */ + if ((sig_inObj->nU == 0) && (sig_inObj->voiced_p == 1)) { + /* purely voiced */ + for (nI = 0; nI < sig_inObj->nV; nI++) { + f = sig_inObj->EnV[nI]; + a = 0; + cnt = PICODSP_FFTSIZE; + ff = (f * window[sig_inObj->LocV[nI]]) >> PICODSP_SHIFT_FACT1; + t1 = &(v1[a + sig_inObj->LocV[nI]]); + t2 = &(fr[a]); + if (cnt > 0)FAST_DEVICE(cnt,*(t1++)+=*(t2++)*ff;); + } + } else if ((sig_inObj->nV == 0) && (sig_inObj->voiced_p == 0)) { + /* PURELY UNVOICED*/ + for (nI = 0; nI < sig_inObj->nU; nI++) { + f = sig_inObj->EnU[nI]; + s = -s; /*reverse order to reduce the periodicity effect*/ + if (s == 1) { + a = 0; + cnt = PICODSP_FFTSIZE; + ff = (f * window[sig_inObj->LocU[nI]]) >> PICODSP_SHIFT_FACT1; + t1 = &(v1[a + sig_inObj->LocU[nI]]); + t2 = &(fr[a]); + if (cnt > 0)FAST_DEVICE(cnt,*(t1++)+=*(t2++)*ff; ); + } else { /*s==-1*/ + a = 0; + cnt = PICODSP_FFTSIZE; + ff = (f * window[sig_inObj->LocU[nI]]) >> PICODSP_SHIFT_FACT1; + t1 = &(v1[(m2 - 1 - a) + sig_inObj->LocU[nI]]); + t2 = &(fr[a]); + if (cnt > 0)FAST_DEVICE(cnt,*(t1--)+=*(t2++)*ff; ); + } + } + } else if (sig_inObj->VoicTrans == 0) { + /*voicing transition from unvoiced to voiced*/ + for (nI = 0; nI < sig_inObj->nV; nI++) { + f = sig_inObj->EnV[nI]; + a = 0; + cnt = PICODSP_FFTSIZE; + ff = (f * window[sig_inObj->LocV[nI]]) >> PICODSP_SHIFT_FACT1; + t1 = &(v1[a + sig_inObj->LocV[nI]]); + t2 = &(fr[a]); + if (cnt > 0)FAST_DEVICE(cnt,*(t1++)+=*(t2++)*ff;); + } + /*add remaining stuff from unvoiced part*/ + for (nI = 0; nI < sig_inObj->nU; nI++) { + f = sig_inObj->EnU[nI]; + s = -s; /*reverse order to reduce the periodicity effect*/ + if (s == 1) { + a = 0; + cnt = PICODSP_FFTSIZE; + ff = (f * window[sig_inObj->LocU[nI]]) >> PICODSP_SHIFT_FACT1; + t1 = &(v1[a + sig_inObj->LocU[nI]]); + t2 = &(sig_inObj->ImpResp_p[a]); /*saved impulse response*/ + if (cnt > 0)FAST_DEVICE(cnt,*(t1++)+=*(t2++)*ff; ); + } else { + a = 0; + cnt = PICODSP_FFTSIZE; + ff = (f * window[sig_inObj->LocU[nI]]) >> PICODSP_SHIFT_FACT1; + t1 = &(v1[(m2 - 1 - a) + sig_inObj->LocU[nI]]); + t2 = &(sig_inObj->ImpResp_p[a]); + if (cnt > 0)FAST_DEVICE(cnt,*(t1--)+=*(t2++)*ff; ); + } + } + } else { + /*voiced to unvoiced*/ + for (nI = 0; nI < sig_inObj->nU; nI++) { + f = sig_inObj->EnU[nI]; + s = -s; /*reverse order to reduce the periodicity effect*/ + if (s > 0) { + a = 0; + cnt = PICODSP_FFTSIZE; + ff = (f * window[sig_inObj->LocU[nI]]) >> PICODSP_SHIFT_FACT1; + t1 = &(v1[a + sig_inObj->LocU[nI]]); + t2 = &(fr[a]); + if (cnt > 0)FAST_DEVICE(cnt,*(t1++)+=*(t2++)*ff; ); + } else { + a = 0; + cnt = PICODSP_FFTSIZE; + ff = (f * window[sig_inObj->LocU[nI]]) >> PICODSP_SHIFT_FACT1; + t1 = &(v1[(m2 - 1 - a) + sig_inObj->LocU[nI]]); + t2 = &(fr[a]); + if (cnt > 0)FAST_DEVICE(cnt,*(t1--)+=*(t2++)*ff; ); + } + } + /*add remaining stuff from voiced part*/ + for (nI = 0; nI < sig_inObj->nV; nI++) { + f = sig_inObj->EnV[nI]; + a = 0; + cnt = PICODSP_FFTSIZE; + ff = (f * window[sig_inObj->LocV[nI]]) >> PICODSP_SHIFT_FACT1; + t1 = &(v1[a + sig_inObj->LocV[nI]]); + t2 = &(sig_inObj->ImpResp_p[a]); + if (cnt > 0)FAST_DEVICE(cnt,*(t1++)+=*(t2++)*ff;); + } + } + + t1 = sig_inObj->sig_vec1; + for (i = 0; i < PICODSP_FFTSIZE; i++, t1++) { + if (*t1 >= 0) + *t1 >>= PICODSP_SHIFT_FACT5; + else + *t1 = -((-*t1) >> PICODSP_SHIFT_FACT5); + } + +}/*td_psola2*/ + +/** + * overlap + add summing of impulse responses on the final destination sample buffer + * @param sig_inObj : sig PU internal object of the sub-object + * @return void + * @remarks Special treatment at voicing boundaries + * @remarks Introduced to get rid of time-domain aliasing (and additional speed up) + * Input + * - wlet : the generic impulse response (FFT size, real) + * - window : the windowing funcion (FFT size, real) fixed + * - WavBuff : the destination buffer with past samples (FFT size*2, short) + * - m2 : fftsize + * Output + * - WavBuff : the destination buffer with updated samples (FFT size*2, short) + * @callgraph + * @callergraph + */ +void overlap_add(sig_innerobj_t *sig_inObj) +{ + /*Local variables*/ + picoos_int32 *w, *v; + + /*Link local variables with sig object*/ + w = sig_inObj->WavBuff_p; + v = sig_inObj->sig_vec1; + + FAST_DEVICE(PICODSP_FFTSIZE, + if (*v >= 0) + *(w++)+=*(v++)<window_p; + norm = sig_inObj->norm_window_p; + + norm[0] = 80224; + norm[1] = 320832; + norm[2] = 721696; + norm[3] = 1282560; + norm[4] = 2003104; + norm[5] = 2882880; + norm[6] = 3921376; + norm[7] = 5117984; + norm[8] = 6471952; + norm[9] = 7982496; + norm[10] = 9648720; + norm[11] = 11469616; + norm[12] = 13444080; + norm[13] = 15570960; + norm[14] = 17848976; + norm[15] = 20276752; + norm[16] = 22852864; + norm[17] = 25575744; + norm[18] = 28443776; + norm[19] = 31455264; + norm[20] = 34608368; + norm[21] = 37901248; + norm[22] = 41331904; + norm[23] = 44898304; + norm[24] = 48598304; + norm[25] = 52429696; + norm[26] = 56390192; + norm[27] = 60477408; + norm[28] = 64688944; + norm[29] = 69022240; + norm[30] = 73474720; + norm[31] = 78043744; + norm[32] = 82726544; + norm[33] = 87520352; + norm[34] = 92422272; + norm[35] = 97429408; + norm[36] = 102538752; + norm[37] = 107747248; + norm[38] = 113051776; + norm[39] = 118449184; + norm[40] = 123936224; + norm[41] = 129509648; + norm[42] = 135166080; + norm[43] = 140902192; + norm[44] = 146714528; + norm[45] = 152599584; + norm[46] = 158553904; + norm[47] = 164573888; + norm[48] = 170655936; + norm[49] = 176796448; + norm[50] = 182991712; + norm[51] = 189238064; + norm[52] = 195531744; + norm[53] = 201868992; + norm[54] = 208246016; + norm[55] = 214659040; + norm[56] = 221104176; + norm[57] = 227577616; + norm[58] = 234075488; + norm[59] = 240593872; + norm[60] = 247128912; + norm[61] = 253676688; + norm[62] = 260233280; + norm[63] = 266794768; + norm[64] = 273357248; + norm[65] = 279916768; + norm[66] = 286469440; + norm[67] = 293011360; + norm[68] = 299538560; + norm[69] = 306047168; + norm[70] = 312533312; + norm[71] = 318993088; + norm[72] = 325422656; + norm[73] = 331818144; + norm[74] = 338175744; + norm[75] = 344491680; + norm[76] = 350762176; + norm[77] = 356983424; + norm[78] = 363151808; + norm[79] = 369263520; + norm[80] = 375315008; + norm[81] = 381302592; + norm[82] = 387222720; + norm[83] = 393071872; + norm[84] = 398846528; + norm[85] = 404543232; + norm[86] = 410158560; + norm[87] = 415689216; + norm[88] = 421131840; + norm[89] = 426483200; + norm[90] = 431740096; + norm[91] = 436899392; + norm[92] = 441958016; + norm[93] = 446912928; + norm[94] = 451761152; + norm[95] = 456499840; + norm[96] = 461126080; + norm[97] = 465637152; + norm[98] = 470030400; + norm[99] = 474303104; + norm[100] = 478452800; + norm[101] = 482476960; + norm[102] = 486373184; + norm[103] = 490139200; + norm[104] = 493772640; + norm[105] = 497271424; + norm[106] = 500633440; + norm[107] = 503856704; + norm[108] = 506939200; + norm[109] = 509879168; + norm[110] = 512674880; + norm[111] = 515324544; + norm[112] = 517826688; + norm[113] = 520179776; + norm[114] = 522382368; + norm[115] = 524433184; + norm[116] = 526331008; + norm[117] = 528074688; + norm[118] = 529663200; + norm[119] = 531095552; + norm[120] = 532370944; + norm[121] = 533488576; + norm[122] = 534447808; + norm[123] = 535248000; + norm[124] = 535888768; + norm[125] = 536369664; + norm[126] = 536690432; + norm[127] = 536850880; + norm[128] = 536850880; + norm[129] = 536690432; + norm[130] = 536369664; + norm[131] = 535888768; + norm[132] = 535248000; + norm[133] = 534447808; + norm[134] = 533488576; + norm[135] = 532370944; + norm[136] = 531095552; + norm[137] = 529663200; + norm[138] = 528074688; + norm[139] = 526331008; + norm[140] = 524433216; + norm[141] = 522382368; + norm[142] = 520179776; + norm[143] = 517826688; + norm[144] = 515324544; + norm[145] = 512674880; + norm[146] = 509879168; + norm[147] = 506939200; + norm[148] = 503856704; + norm[149] = 500633472; + norm[150] = 497271424; + norm[151] = 493772672; + norm[152] = 490139200; + norm[153] = 486373184; + norm[154] = 482476992; + norm[155] = 478452800; + norm[156] = 474303104; + norm[157] = 470030400; + norm[158] = 465637184; + norm[159] = 461126080; + norm[160] = 456499840; + norm[161] = 451761152; + norm[162] = 446912960; + norm[163] = 441958016; + norm[164] = 436899424; + norm[165] = 431740096; + norm[166] = 426483200; + norm[167] = 421131840; + norm[168] = 415689216; + norm[169] = 410158560; + norm[170] = 404543232; + norm[171] = 398846528; + norm[172] = 393071872; + norm[173] = 387222720; + norm[174] = 381302592; + norm[175] = 375315008; + norm[176] = 369263552; + norm[177] = 363151808; + norm[178] = 356983456; + norm[179] = 350762176; + norm[180] = 344491712; + norm[181] = 338175776; + norm[182] = 331818144; + norm[183] = 325422656; + norm[184] = 318993088; + norm[185] = 312533312; + norm[186] = 306047168; + norm[187] = 299538560; + norm[188] = 293011360; + norm[189] = 286469472; + norm[190] = 279916800; + norm[191] = 273357248; + norm[192] = 266794784; + norm[193] = 260233280; + norm[194] = 253676688; + norm[195] = 247128928; + norm[196] = 240593888; + norm[197] = 234075488; + norm[198] = 227577632; + norm[199] = 221104192; + norm[200] = 214659040; + norm[201] = 208246032; + norm[202] = 201868992; + norm[203] = 195531744; + norm[204] = 189238080; + norm[205] = 182991728; + norm[206] = 176796448; + norm[207] = 170655952; + norm[208] = 164573888; + norm[209] = 158553920; + norm[210] = 152599600; + norm[211] = 146714528; + norm[212] = 140902208; + norm[213] = 135166096; + norm[214] = 129509648; + norm[215] = 123936240; + norm[216] = 118449184; + norm[217] = 113051776; + norm[218] = 107747248; + norm[219] = 102538752; + norm[220] = 97429424; + norm[221] = 92422288; + norm[222] = 87520352; + norm[223] = 82726544; + norm[224] = 78043744; + norm[225] = 73474736; + norm[226] = 69022240; + norm[227] = 64688944; + norm[228] = 60477424; + norm[229] = 56390192; + norm[230] = 52429696; + norm[231] = 48598304; + norm[232] = 44898304; + norm[233] = 41331904; + norm[234] = 37901248; + norm[235] = 34608384; + norm[236] = 31455264; + norm[237] = 28443792; + norm[238] = 25575744; + norm[239] = 22852864; + norm[240] = 20276752; + norm[241] = 17848976; + norm[242] = 15570960; + norm[243] = 13444080; + norm[244] = 11469616; + norm[245] = 9648720; + norm[246] = 7982512; + norm[247] = 6471952; + norm[248] = 5117984; + norm[249] = 3921376; + norm[250] = 2882880; + norm[251] = 2003104; + norm[252] = 1282560; + norm[253] = 721696; + norm[254] = 320832; + norm[255] = 80224; + hann[0] = 0; + hann[1] = 0; + hann[2] = 1; + hann[3] = 2; + hann[4] = 3; + hann[5] = 5; + hann[6] = 7; + hann[7] = 9; + hann[8] = 12; + hann[9] = 15; + hann[10] = 18; + hann[11] = 21; + hann[12] = 25; + hann[13] = 29; + hann[14] = 34; + hann[15] = 38; + hann[16] = 43; + hann[17] = 48; + hann[18] = 54; + hann[19] = 59; + hann[20] = 66; + hann[21] = 72; + hann[22] = 78; + hann[23] = 85; + hann[24] = 92; + hann[25] = 100; + hann[26] = 107; + hann[27] = 115; + hann[28] = 123; + hann[29] = 131; + hann[30] = 140; + hann[31] = 148; + hann[32] = 157; + hann[33] = 166; + hann[34] = 176; + hann[35] = 185; + hann[36] = 195; + hann[37] = 205; + hann[38] = 215; + hann[39] = 225; + hann[40] = 236; + hann[41] = 247; + hann[42] = 257; + hann[43] = 268; + hann[44] = 279; + hann[45] = 291; + hann[46] = 302; + hann[47] = 313; + hann[48] = 325; + hann[49] = 337; + hann[50] = 349; + hann[51] = 360; + hann[52] = 372; + hann[53] = 385; + hann[54] = 397; + hann[55] = 409; + hann[56] = 421; + hann[57] = 434; + hann[58] = 446; + hann[59] = 458; + hann[60] = 471; + hann[61] = 483; + hann[62] = 496; + hann[63] = 508; + hann[64] = 521; + hann[65] = 533; + hann[66] = 546; + hann[67] = 558; + hann[68] = 571; + hann[69] = 583; + hann[70] = 596; + hann[71] = 608; + hann[72] = 620; + hann[73] = 632; + hann[74] = 645; + hann[75] = 657; + hann[76] = 669; + hann[77] = 680; + hann[78] = 692; + hann[79] = 704; + hann[80] = 715; + hann[81] = 727; + hann[82] = 738; + hann[83] = 749; + hann[84] = 760; + hann[85] = 771; + hann[86] = 782; + hann[87] = 792; + hann[88] = 803; + hann[89] = 813; + hann[90] = 823; + hann[91] = 833; + hann[92] = 842; + hann[93] = 852; + hann[94] = 861; + hann[95] = 870; + hann[96] = 879; + hann[97] = 888; + hann[98] = 896; + hann[99] = 904; + hann[100] = 912; + hann[101] = 920; + hann[102] = 927; + hann[103] = 934; + hann[104] = 941; + hann[105] = 948; + hann[106] = 954; + hann[107] = 961; + hann[108] = 966; + hann[109] = 972; + hann[110] = 977; + hann[111] = 982; + hann[112] = 987; + hann[113] = 992; + hann[114] = 996; + hann[115] = 1000; + hann[116] = 1003; + hann[117] = 1007; + hann[118] = 1010; + hann[119] = 1012; + hann[120] = 1015; + hann[121] = 1017; + hann[122] = 1019; + hann[123] = 1020; + hann[124] = 1022; + hann[125] = 1023; + hann[126] = 1023; + hann[127] = 1023; + hann[128] = 1023; + hann[129] = 1023; + hann[130] = 1023; + hann[131] = 1022; + hann[132] = 1020; + hann[133] = 1019; + hann[134] = 1017; + hann[135] = 1015; + hann[136] = 1012; + hann[137] = 1010; + hann[138] = 1007; + hann[139] = 1003; + hann[140] = 1000; + hann[141] = 996; + hann[142] = 992; + hann[143] = 987; + hann[144] = 982; + hann[145] = 977; + hann[146] = 972; + hann[147] = 966; + hann[148] = 961; + hann[149] = 954; + hann[150] = 948; + hann[151] = 941; + hann[152] = 934; + hann[153] = 927; + hann[154] = 920; + hann[155] = 912; + hann[156] = 904; + hann[157] = 896; + hann[158] = 888; + hann[159] = 879; + hann[160] = 870; + hann[161] = 861; + hann[162] = 852; + hann[163] = 842; + hann[164] = 833; + hann[165] = 823; + hann[166] = 813; + hann[167] = 803; + hann[168] = 792; + hann[169] = 782; + hann[170] = 771; + hann[171] = 760; + hann[172] = 749; + hann[173] = 738; + hann[174] = 727; + hann[175] = 715; + hann[176] = 704; + hann[177] = 692; + hann[178] = 680; + hann[179] = 669; + hann[180] = 657; + hann[181] = 645; + hann[182] = 632; + hann[183] = 620; + hann[184] = 608; + hann[185] = 596; + hann[186] = 583; + hann[187] = 571; + hann[188] = 558; + hann[189] = 546; + hann[190] = 533; + hann[191] = 521; + hann[192] = 508; + hann[193] = 496; + hann[194] = 483; + hann[195] = 471; + hann[196] = 458; + hann[197] = 446; + hann[198] = 434; + hann[199] = 421; + hann[200] = 409; + hann[201] = 397; + hann[202] = 385; + hann[203] = 372; + hann[204] = 360; + hann[205] = 349; + hann[206] = 337; + hann[207] = 325; + hann[208] = 313; + hann[209] = 302; + hann[210] = 291; + hann[211] = 279; + hann[212] = 268; + hann[213] = 257; + hann[214] = 247; + hann[215] = 236; + hann[216] = 225; + hann[217] = 215; + hann[218] = 205; + hann[219] = 195; + hann[220] = 185; + hann[221] = 176; + hann[222] = 166; + hann[223] = 157; + hann[224] = 148; + hann[225] = 140; + hann[226] = 131; + hann[227] = 123; + hann[228] = 115; + hann[229] = 107; + hann[230] = 100; + hann[231] = 92; + hann[232] = 85; + hann[233] = 78; + hann[234] = 72; + hann[235] = 66; + hann[236] = 59; + hann[237] = 54; + hann[238] = 48; + hann[239] = 43; + hann[240] = 38; + hann[241] = 34; + hann[242] = 29; + hann[243] = 25; + hann[244] = 21; + hann[245] = 18; + hann[246] = 15; + hann[247] = 12; + hann[248] = 9; + hann[249] = 7; + hann[250] = 5; + hann[251] = 3; + hann[252] = 2; + hann[253] = 1; + hann[254] = 0; + hann[255] = 0; + +} /* gen_hann2 */ + +/** + * Creates the non uniform enhancement window (bilinearly mapped hannning window) + * in order to reduce the formant enhancement in the high spectrum + * @param mm : memory manager + * @param sig_inObj : sig PU internal object of the sub-object + * @return void + * @callgraph + * @callergraph + * @remarks the outgput is based on the matlab script below\n + matlab script + ------------- + function makeEnhWind(alpha) + N=129; % =HFFTSIZEE_P1 + s=(bilinmap(alpha,N)); + h=[hann(N)']; + x=(1:N)/N; + W=interp1(x,h,s); W(1)=0; + + fid=fopen('enhwind.txt','wt'); + fprintf(fid,'picoos_int16 enh_wind_init(sig_innerobj_t *sig_inObj) {\n'); + for i=1:N, + fprintf(fid,[' sig_inObj->enhwind[' int2str(i) '] = (picoos_single)' num2str(W(i),'%0.7g') ';\n']); + end; + fprintf(fid,' return PICO_OK;\n'); + fprintf(fid,' }; \n'); + fclose(fid); + %figure(1); plot(x*8,W); + */ +static void enh_wind_init(sig_innerobj_t *sig_inObj) +{ + /* picoos_int16 i; */ + picoos_int32 *c; + + c = sig_inObj->cos_table; + + c[0] = 4096; + c[1] = 4095; + c[2] = 4095; + c[3] = 4095; + c[4] = 4095; + c[5] = 4095; + c[6] = 4095; + c[7] = 4095; + c[8] = 4094; + c[9] = 4094; + c[10] = 4094; + c[11] = 4093; + c[12] = 4093; + c[13] = 4092; + c[14] = 4092; + c[15] = 4091; + c[16] = 4091; + c[17] = 4090; + c[18] = 4089; + c[19] = 4089; + c[20] = 4088; + c[21] = 4087; + c[22] = 4086; + c[23] = 4085; + c[24] = 4084; + c[25] = 4083; + c[26] = 4082; + c[27] = 4081; + c[28] = 4080; + c[29] = 4079; + c[30] = 4078; + c[31] = 4077; + c[32] = 4076; + c[33] = 4075; + c[34] = 4073; + c[35] = 4072; + c[36] = 4071; + c[37] = 4069; + c[38] = 4068; + c[39] = 4066; + c[40] = 4065; + c[41] = 4063; + c[42] = 4062; + c[43] = 4060; + c[44] = 4058; + c[45] = 4057; + c[46] = 4055; + c[47] = 4053; + c[48] = 4051; + c[49] = 4049; + c[50] = 4047; + c[51] = 4045; + c[52] = 4043; + c[53] = 4041; + c[54] = 4039; + c[55] = 4037; + c[56] = 4035; + c[57] = 4033; + c[58] = 4031; + c[59] = 4029; + c[60] = 4026; + c[61] = 4024; + c[62] = 4022; + c[63] = 4019; + c[64] = 4017; + c[65] = 4014; + c[66] = 4012; + c[67] = 4009; + c[68] = 4007; + c[69] = 4004; + c[70] = 4001; + c[71] = 3999; + c[72] = 3996; + c[73] = 3993; + c[74] = 3990; + c[75] = 3988; + c[76] = 3985; + c[77] = 3982; + c[78] = 3979; + c[79] = 3976; + c[80] = 3973; + c[81] = 3970; + c[82] = 3967; + c[83] = 3963; + c[84] = 3960; + c[85] = 3957; + c[86] = 3954; + c[87] = 3950; + c[88] = 3947; + c[89] = 3944; + c[90] = 3940; + c[91] = 3937; + c[92] = 3933; + c[93] = 3930; + c[94] = 3926; + c[95] = 3923; + c[96] = 3919; + c[97] = 3915; + c[98] = 3912; + c[99] = 3908; + c[100] = 3904; + c[101] = 3900; + c[102] = 3897; + c[103] = 3893; + c[104] = 3889; + c[105] = 3885; + c[106] = 3881; + c[107] = 3877; + c[108] = 3873; + c[109] = 3869; + c[110] = 3864; + c[111] = 3860; + c[112] = 3856; + c[113] = 3852; + c[114] = 3848; + c[115] = 3843; + c[116] = 3839; + c[117] = 3834; + c[118] = 3830; + c[119] = 3826; + c[120] = 3821; + c[121] = 3816; + c[122] = 3812; + c[123] = 3807; + c[124] = 3803; + c[125] = 3798; + c[126] = 3793; + c[127] = 3789; + c[128] = 3784; + c[129] = 3779; + c[130] = 3774; + c[131] = 3769; + c[132] = 3764; + c[133] = 3759; + c[134] = 3754; + c[135] = 3749; + c[136] = 3744; + c[137] = 3739; + c[138] = 3734; + c[139] = 3729; + c[140] = 3723; + c[141] = 3718; + c[142] = 3713; + c[143] = 3708; + c[144] = 3702; + c[145] = 3697; + c[146] = 3691; + c[147] = 3686; + c[148] = 3680; + c[149] = 3675; + c[150] = 3669; + c[151] = 3664; + c[152] = 3658; + c[153] = 3652; + c[154] = 3647; + c[155] = 3641; + c[156] = 3635; + c[157] = 3629; + c[158] = 3624; + c[159] = 3618; + c[160] = 3612; + c[161] = 3606; + c[162] = 3600; + c[163] = 3594; + c[164] = 3588; + c[165] = 3582; + c[166] = 3576; + c[167] = 3570; + c[168] = 3563; + c[169] = 3557; + c[170] = 3551; + c[171] = 3545; + c[172] = 3538; + c[173] = 3532; + c[174] = 3526; + c[175] = 3519; + c[176] = 3513; + c[177] = 3506; + c[178] = 3500; + c[179] = 3493; + c[180] = 3487; + c[181] = 3480; + c[182] = 3473; + c[183] = 3467; + c[184] = 3460; + c[185] = 3453; + c[186] = 3447; + c[187] = 3440; + c[188] = 3433; + c[189] = 3426; + c[190] = 3419; + c[191] = 3412; + c[192] = 3405; + c[193] = 3398; + c[194] = 3391; + c[195] = 3384; + c[196] = 3377; + c[197] = 3370; + c[198] = 3363; + c[199] = 3356; + c[200] = 3348; + c[201] = 3341; + c[202] = 3334; + c[203] = 3326; + c[204] = 3319; + c[205] = 3312; + c[206] = 3304; + c[207] = 3297; + c[208] = 3289; + c[209] = 3282; + c[210] = 3274; + c[211] = 3267; + c[212] = 3259; + c[213] = 3252; + c[214] = 3244; + c[215] = 3236; + c[216] = 3229; + c[217] = 3221; + c[218] = 3213; + c[219] = 3205; + c[220] = 3197; + c[221] = 3190; + c[222] = 3182; + c[223] = 3174; + c[224] = 3166; + c[225] = 3158; + c[226] = 3150; + c[227] = 3142; + c[228] = 3134; + c[229] = 3126; + c[230] = 3117; + c[231] = 3109; + c[232] = 3101; + c[233] = 3093; + c[234] = 3085; + c[235] = 3076; + c[236] = 3068; + c[237] = 3060; + c[238] = 3051; + c[239] = 3043; + c[240] = 3034; + c[241] = 3026; + c[242] = 3018; + c[243] = 3009; + c[244] = 3000; + c[245] = 2992; + c[246] = 2983; + c[247] = 2975; + c[248] = 2966; + c[249] = 2957; + c[250] = 2949; + c[251] = 2940; + c[252] = 2931; + c[253] = 2922; + c[254] = 2914; + c[255] = 2905; + c[256] = 2896; + c[257] = 2887; + c[258] = 2878; + c[259] = 2869; + c[260] = 2860; + c[261] = 2851; + c[262] = 2842; + c[263] = 2833; + c[264] = 2824; + c[265] = 2815; + c[266] = 2806; + c[267] = 2796; + c[268] = 2787; + c[269] = 2778; + c[270] = 2769; + c[271] = 2760; + c[272] = 2750; + c[273] = 2741; + c[274] = 2732; + c[275] = 2722; + c[276] = 2713; + c[277] = 2703; + c[278] = 2694; + c[279] = 2684; + c[280] = 2675; + c[281] = 2665; + c[282] = 2656; + c[283] = 2646; + c[284] = 2637; + c[285] = 2627; + c[286] = 2617; + c[287] = 2608; + c[288] = 2598; + c[289] = 2588; + c[290] = 2578; + c[291] = 2569; + c[292] = 2559; + c[293] = 2549; + c[294] = 2539; + c[295] = 2529; + c[296] = 2519; + c[297] = 2510; + c[298] = 2500; + c[299] = 2490; + c[300] = 2480; + c[301] = 2470; + c[302] = 2460; + c[303] = 2450; + c[304] = 2439; + c[305] = 2429; + c[306] = 2419; + c[307] = 2409; + c[308] = 2399; + c[309] = 2389; + c[310] = 2379; + c[311] = 2368; + c[312] = 2358; + c[313] = 2348; + c[314] = 2337; + c[315] = 2327; + c[316] = 2317; + c[317] = 2306; + c[318] = 2296; + c[319] = 2286; + c[320] = 2275; + c[321] = 2265; + c[322] = 2254; + c[323] = 2244; + c[324] = 2233; + c[325] = 2223; + c[326] = 2212; + c[327] = 2201; + c[328] = 2191; + c[329] = 2180; + c[330] = 2170; + c[331] = 2159; + c[332] = 2148; + c[333] = 2138; + c[334] = 2127; + c[335] = 2116; + c[336] = 2105; + c[337] = 2094; + c[338] = 2084; + c[339] = 2073; + c[340] = 2062; + c[341] = 2051; + c[342] = 2040; + c[343] = 2029; + c[344] = 2018; + c[345] = 2007; + c[346] = 1997; + c[347] = 1986; + c[348] = 1975; + c[349] = 1964; + c[350] = 1952; + c[351] = 1941; + c[352] = 1930; + c[353] = 1919; + c[354] = 1908; + c[355] = 1897; + c[356] = 1886; + c[357] = 1875; + c[358] = 1864; + c[359] = 1852; + c[360] = 1841; + c[361] = 1830; + c[362] = 1819; + c[363] = 1807; + c[364] = 1796; + c[365] = 1785; + c[366] = 1773; + c[367] = 1762; + c[368] = 1751; + c[369] = 1739; + c[370] = 1728; + c[371] = 1717; + c[372] = 1705; + c[373] = 1694; + c[374] = 1682; + c[375] = 1671; + c[376] = 1659; + c[377] = 1648; + c[378] = 1636; + c[379] = 1625; + c[380] = 1613; + c[381] = 1602; + c[382] = 1590; + c[383] = 1579; + c[384] = 1567; + c[385] = 1555; + c[386] = 1544; + c[387] = 1532; + c[388] = 1520; + c[389] = 1509; + c[390] = 1497; + c[391] = 1485; + c[392] = 1474; + c[393] = 1462; + c[394] = 1450; + c[395] = 1438; + c[396] = 1427; + c[397] = 1415; + c[398] = 1403; + c[399] = 1391; + c[400] = 1379; + c[401] = 1368; + c[402] = 1356; + c[403] = 1344; + c[404] = 1332; + c[405] = 1320; + c[406] = 1308; + c[407] = 1296; + c[408] = 1284; + c[409] = 1272; + c[410] = 1260; + c[411] = 1248; + c[412] = 1237; + c[413] = 1225; + c[414] = 1213; + c[415] = 1201; + c[416] = 1189; + c[417] = 1176; + c[418] = 1164; + c[419] = 1152; + c[420] = 1140; + c[421] = 1128; + c[422] = 1116; + c[423] = 1104; + c[424] = 1092; + c[425] = 1080; + c[426] = 1068; + c[427] = 1056; + c[428] = 1043; + c[429] = 1031; + c[430] = 1019; + c[431] = 1007; + c[432] = 995; + c[433] = 983; + c[434] = 970; + c[435] = 958; + c[436] = 946; + c[437] = 934; + c[438] = 921; + c[439] = 909; + c[440] = 897; + c[441] = 885; + c[442] = 872; + c[443] = 860; + c[444] = 848; + c[445] = 836; + c[446] = 823; + c[447] = 811; + c[448] = 799; + c[449] = 786; + c[450] = 774; + c[451] = 762; + c[452] = 749; + c[453] = 737; + c[454] = 725; + c[455] = 712; + c[456] = 700; + c[457] = 687; + c[458] = 675; + c[459] = 663; + c[460] = 650; + c[461] = 638; + c[462] = 625; + c[463] = 613; + c[464] = 601; + c[465] = 588; + c[466] = 576; + c[467] = 563; + c[468] = 551; + c[469] = 538; + c[470] = 526; + c[471] = 513; + c[472] = 501; + c[473] = 488; + c[474] = 476; + c[475] = 463; + c[476] = 451; + c[477] = 438; + c[478] = 426; + c[479] = 413; + c[480] = 401; + c[481] = 388; + c[482] = 376; + c[483] = 363; + c[484] = 351; + c[485] = 338; + c[486] = 326; + c[487] = 313; + c[488] = 301; + c[489] = 288; + c[490] = 276; + c[491] = 263; + c[492] = 251; + c[493] = 238; + c[494] = 226; + c[495] = 213; + c[496] = 200; + c[497] = 188; + c[498] = 175; + c[499] = 163; + c[500] = 150; + c[501] = 138; + c[502] = 125; + c[503] = 113; + c[504] = 100; + c[505] = 87; + c[506] = 75; + c[507] = 62; + c[508] = 50; + c[509] = 37; + c[510] = 25; + c[511] = 12; + c[512] = 0; +} /*enh_wind_init*/ + +/** + * Initializes a useful large array of random numbers + * @param sig_inObj : sig PU internal object of the sub-object + * @return void + * @callgraph + * @callergraph + */ +static void init_rand(sig_innerobj_t *sig_inObj) +{ + picoos_int32 *q = sig_inObj->int_vec34; + picoos_int32 *r = sig_inObj->int_vec35; + + sig_inObj->iRand = 0; + + q[0] = -2198; + r[0] = 3455; + q[1] = 3226; + r[1] = -2522; + q[2] = -845; + r[2] = 4007; + q[3] = -1227; + r[3] = 3907; + q[4] = -3480; + r[4] = 2158; + q[5] = -1325; + r[5] = -3875; + q[6] = 2089; + r[6] = -3522; + q[7] = -468; + r[7] = 4069; + q[8] = 711; + r[8] = -4033; + q[9] = 3862; + r[9] = 1362; + q[10] = 4054; + r[10] = -579; + q[11] = 2825; + r[11] = 2965; + q[12] = 2704; + r[12] = -3076; + q[13] = 4081; + r[13] = 344; + q[14] = -3912; + r[14] = 1211; + q[15] = -3541; + r[15] = 2058; + q[16] = 2694; + r[16] = 3084; + q[17] = 835; + r[17] = 4009; + q[18] = -2578; + r[18] = -3182; + q[19] = 3205; + r[19] = 2550; + q[20] = -4074; + r[20] = -418; + q[21] = -183; + r[21] = -4091; + q[22] = -2665; + r[22] = -3110; + q[23] = -1367; + r[23] = 3860; + q[24] = -2266; + r[24] = -3411; + q[25] = 3327; + r[25] = -2387; + q[26] = -2807; + r[26] = -2982; + q[27] = -3175; + r[27] = -2587; + q[28] = -4095; + r[28] = 27; + q[29] = -811; + r[29] = -4014; + q[30] = 4082; + r[30] = 332; + q[31] = -2175; + r[31] = 3470; + q[32] = 3112; + r[32] = 2662; + q[33] = 1168; + r[33] = -3925; + q[34] = 2659; + r[34] = 3115; + q[35] = 4048; + r[35] = 622; + q[36] = 4092; + r[36] = -165; + q[37] = -4036; + r[37] = 697; + q[38] = 1081; + r[38] = -3950; + q[39] = -548; + r[39] = 4059; + q[40] = 4038; + r[40] = 685; + q[41] = -511; + r[41] = 4063; + q[42] = 3317; + r[42] = -2402; + q[43] = -3180; + r[43] = 2580; + q[44] = 851; + r[44] = -4006; + q[45] = 2458; + r[45] = -3276; + q[46] = -1453; + r[46] = 3829; + q[47] = -3577; + r[47] = 1995; + q[48] = -3708; + r[48] = -1738; + q[49] = -3890; + r[49] = 1282; + q[50] = 4041; + r[50] = 666; + q[51] = -3511; + r[51] = -2108; + q[52] = -1454; + r[52] = -3828; + q[53] = 2124; + r[53] = 3502; + q[54] = -3159; + r[54] = 2606; + q[55] = 2384; + r[55] = -3330; + q[56] = -3767; + r[56] = -1607; + q[57] = -4063; + r[57] = -513; + q[58] = 3952; + r[58] = -1075; + q[59] = -3778; + r[59] = -1581; + q[60] = -301; + r[60] = -4084; + q[61] = -4026; + r[61] = 751; + q[62] = -3346; + r[62] = 2361; + q[63] = -2426; + r[63] = 3299; + q[64] = 428; + r[64] = -4073; + q[65] = 3968; + r[65] = 1012; + q[66] = 2900; + r[66] = -2892; + q[67] = -263; + r[67] = 4087; + q[68] = 4083; + r[68] = 322; + q[69] = 2024; + r[69] = 3560; + q[70] = 4015; + r[70] = 808; + q[71] = -3971; + r[71] = -1000; + q[72] = 3785; + r[72] = -1564; + q[73] = -3726; + r[73] = 1701; + q[74] = -3714; + r[74] = 1725; + q[75] = 743; + r[75] = 4027; + q[76] = 875; + r[76] = -4001; + q[77] = 294; + r[77] = 4085; + q[78] = 2611; + r[78] = 3155; + q[79] = 2491; + r[79] = -3251; + q[80] = 1558; + r[80] = 3787; + q[81] = -2063; + r[81] = -3538; + q[82] = 3809; + r[82] = -1505; + q[83] = -2987; + r[83] = 2802; + q[84] = -1955; + r[84] = 3599; + q[85] = 1980; + r[85] = -3585; + q[86] = -539; + r[86] = -4060; + q[87] = -3210; + r[87] = 2543; + q[88] = 2415; + r[88] = -3308; + q[89] = 1587; + r[89] = 3775; + q[90] = -3943; + r[90] = 1106; + q[91] = 3476; + r[91] = 2165; + q[92] = 2253; + r[92] = 3420; + q[93] = -2584; + r[93] = 3177; + q[94] = 3804; + r[94] = -1518; + q[95] = -3637; + r[95] = 1883; + q[96] = 3289; + r[96] = -2440; + q[97] = -1621; + r[97] = 3761; + q[98] = 1645; + r[98] = 3751; + q[99] = -3471; + r[99] = 2173; + q[100] = 4071; + r[100] = -449; + q[101] = -872; + r[101] = -4001; + q[102] = -3897; + r[102] = 1259; + q[103] = -3590; + r[103] = 1970; + q[104] = -2456; + r[104] = -3277; + q[105] = -3004; + r[105] = 2783; + q[106] = 2589; + r[106] = 3173; + q[107] = 3727; + r[107] = -1698; + q[108] = 2992; + r[108] = 2796; + q[109] = 794; + r[109] = -4018; + q[110] = -918; + r[110] = 3991; + q[111] = 1446; + r[111] = -3831; + q[112] = 3871; + r[112] = -1338; + q[113] = -612; + r[113] = -4049; + q[114] = -1566; + r[114] = -3784; + q[115] = 672; + r[115] = -4040; + q[116] = 3841; + r[116] = 1422; + q[117] = 3545; + r[117] = -2051; + q[118] = -1982; + r[118] = -3584; + q[119] = -3413; + r[119] = 2263; + q[120] = -3265; + r[120] = -2473; + q[121] = -2876; + r[121] = -2915; + q[122] = 4094; + r[122] = -117; + q[123] = -269; + r[123] = 4087; + q[124] = -4077; + r[124] = 391; + q[125] = -3759; + r[125] = 1626; + q[126] = 1639; + r[126] = 3753; + q[127] = 3041; + r[127] = -2743; + q[128] = 5; + r[128] = 4095; + q[129] = 2778; + r[129] = -3009; + q[130] = 1121; + r[130] = -3939; + q[131] = -455; + r[131] = -4070; + q[132] = 3532; + r[132] = 2073; + q[133] = -143; + r[133] = -4093; + q[134] = -2357; + r[134] = -3349; + q[135] = 458; + r[135] = 4070; + q[136] = -2887; + r[136] = -2904; + q[137] = -1104; + r[137] = 3944; + q[138] = -2104; + r[138] = -3513; + q[139] = 126; + r[139] = 4094; + q[140] = -3655; + r[140] = -1848; + q[141] = -3896; + r[141] = 1263; + q[142] = -3874; + r[142] = -1327; + q[143] = 4058; + r[143] = 553; + q[144] = -1831; + r[144] = -3663; + q[145] = -255; + r[145] = -4088; + q[146] = -1211; + r[146] = 3912; + q[147] = 445; + r[147] = 4071; + q[148] = 2268; + r[148] = 3410; + q[149] = -4010; + r[149] = 833; + q[150] = 2621; + r[150] = 3147; + q[151] = -250; + r[151] = 4088; + q[152] = -3409; + r[152] = -2269; + q[153] = -2710; + r[153] = -3070; + q[154] = 4063; + r[154] = 518; + q[155] = -3611; + r[155] = -1933; + q[156] = -3707; + r[156] = -1741; + q[157] = -1151; + r[157] = -3930; + q[158] = 3976; + r[158] = -983; + q[159] = -1736; + r[159] = 3709; + q[160] = 3669; + r[160] = 1820; + q[161] = -143; + r[161] = 4093; + q[162] = -3879; + r[162] = -1313; + q[163] = -2242; + r[163] = -3427; + q[164] = -4095; + r[164] = 0; + q[165] = -1159; + r[165] = -3928; + q[166] = -3155; + r[166] = 2611; + q[167] = -2887; + r[167] = -2904; + q[168] = -4095; + r[168] = 56; + q[169] = -3861; + r[169] = -1364; + q[170] = -2814; + r[170] = 2976; + q[171] = -3680; + r[171] = -1798; + q[172] = -4094; + r[172] = -107; + q[173] = -3626; + r[173] = 1903; + q[174] = 3403; + r[174] = 2278; + q[175] = -1735; + r[175] = -3710; + q[176] = -2126; + r[176] = -3500; + q[177] = 3183; + r[177] = -2577; + q[178] = -3499; + r[178] = 2128; + q[179] = -1736; + r[179] = 3709; + q[180] = 2592; + r[180] = -3170; + q[181] = 3875; + r[181] = 1326; + q[182] = 3596; + r[182] = 1960; + q[183] = 3915; + r[183] = -1202; + q[184] = 1570; + r[184] = 3783; + q[185] = -3319; + r[185] = -2400; + q[186] = 4019; + r[186] = 787; + q[187] = -187; + r[187] = 4091; + q[188] = 1370; + r[188] = -3859; + q[189] = -4091; + r[189] = 199; + q[190] = 3626; + r[190] = 1904; + q[191] = -2943; + r[191] = 2848; + q[192] = 56; + r[192] = 4095; + q[193] = 2824; + r[193] = 2966; + q[194] = -3994; + r[194] = -904; + q[195] = 56; + r[195] = 4095; + q[196] = -2045; + r[196] = 3548; + q[197] = -3653; + r[197] = 1850; + q[198] = -2864; + r[198] = 2927; + q[199] = -1996; + r[199] = 3576; + q[200] = -4061; + r[200] = 527; + q[201] = 159; + r[201] = 4092; + q[202] = -3363; + r[202] = 2336; + q[203] = -4074; + r[203] = 421; + q[204] = 2043; + r[204] = 3549; + q[205] = 4095; + r[205] = -70; + q[206] = -2107; + r[206] = -3512; + q[207] = -1973; + r[207] = 3589; + q[208] = -3138; + r[208] = 2631; + q[209] = -3625; + r[209] = -1905; + q[210] = 2413; + r[210] = 3309; + q[211] = -50; + r[211] = -4095; + q[212] = 2813; + r[212] = 2976; + q[213] = -535; + r[213] = -4060; + q[214] = 1250; + r[214] = 3900; + q[215] = 1670; + r[215] = -3739; + q[216] = 1945; + r[216] = -3604; + q[217] = -476; + r[217] = -4068; + q[218] = -3659; + r[218] = -1840; + q[219] = 2745; + r[219] = 3039; + q[220] = -674; + r[220] = -4040; + q[221] = 2383; + r[221] = 3330; + q[222] = 4086; + r[222] = 274; + q[223] = -4030; + r[223] = 730; + q[224] = 768; + r[224] = -4023; + q[225] = 3925; + r[225] = 1170; + q[226] = 785; + r[226] = 4019; + q[227] = -3101; + r[227] = -2675; + q[228] = 4030; + r[228] = -729; + q[229] = 3422; + r[229] = 2249; + q[230] = -3847; + r[230] = 1403; + q[231] = 3902; + r[231] = -1243; + q[232] = 2114; + r[232] = -3507; + q[233] = -2359; + r[233] = 3348; + q[234] = 3754; + r[234] = -1638; + q[235] = -4095; + r[235] = -83; + q[236] = 2301; + r[236] = -3388; + q[237] = 3336; + r[237] = 2375; + q[238] = -2045; + r[238] = 3548; + q[239] = -413; + r[239] = -4075; + q[240] = 1848; + r[240] = 3655; + q[241] = 4072; + r[241] = -437; + q[242] = 4069; + r[242] = -463; + q[243] = 1386; + r[243] = -3854; + q[244] = 966; + r[244] = 3980; + q[245] = -1684; + r[245] = -3733; + q[246] = 2953; + r[246] = 2837; + q[247] = -3961; + r[247] = -1040; + q[248] = 3512; + r[248] = -2107; + q[249] = 1363; + r[249] = 3862; + q[250] = 1883; + r[250] = 3637; + q[251] = 2657; + r[251] = 3116; + q[252] = 2347; + r[252] = -3356; + q[253] = -1635; + r[253] = -3755; + q[254] = 3170; + r[254] = 2593; + q[255] = 2856; + r[255] = 2935; + q[256] = 494; + r[256] = 4066; + q[257] = 1936; + r[257] = -3609; + q[258] = 245; + r[258] = 4088; + q[259] = -1211; + r[259] = -3912; + q[260] = -3600; + r[260] = 1952; + q[261] = 1632; + r[261] = 3756; + q[262] = 2341; + r[262] = 3360; + q[263] = 186; + r[263] = -4091; + q[264] = 4011; + r[264] = 829; + q[265] = -3490; + r[265] = -2143; + q[266] = 269; + r[266] = -4087; + q[267] = -2939; + r[267] = 2852; + q[268] = 1600; + r[268] = 3770; + q[269] = -3405; + r[269] = -2275; + q[270] = -3134; + r[270] = -2636; + q[271] = 2642; + r[271] = -3129; + q[272] = 3629; + r[272] = 1898; + q[273] = 3413; + r[273] = 2264; + q[274] = 2050; + r[274] = 3545; + q[275] = 988; + r[275] = -3975; + q[276] = -660; + r[276] = 4042; + q[277] = 978; + r[277] = -3977; + q[278] = 1965; + r[278] = -3593; + q[279] = -1513; + r[279] = -3806; + q[280] = -4076; + r[280] = 401; + q[281] = -4094; + r[281] = -92; + q[282] = -1914; + r[282] = 3621; + q[283] = 2006; + r[283] = -3570; + q[284] = -1550; + r[284] = -3791; + q[285] = 3774; + r[285] = -1591; + q[286] = -3958; + r[286] = 1052; + q[287] = -3576; + r[287] = 1997; + q[288] = -382; + r[288] = 4078; + q[289] = 1288; + r[289] = 3888; + q[290] = -2965; + r[290] = -2825; + q[291] = 1608; + r[291] = 3767; + q[292] = 3052; + r[292] = -2731; + q[293] = -622; + r[293] = 4048; + q[294] = -3836; + r[294] = 1434; + q[295] = -3542; + r[295] = 2056; + q[296] = -2648; + r[296] = 3124; + q[297] = -1178; + r[297] = -3922; + q[298] = -1109; + r[298] = 3942; + q[299] = 3910; + r[299] = 1217; + q[300] = 1199; + r[300] = -3916; + q[301] = -3386; + r[301] = 2303; + q[302] = -3453; + r[302] = 2202; + q[303] = -2877; + r[303] = 2914; + q[304] = 4095; + r[304] = -47; + q[305] = 3635; + r[305] = 1886; + q[306] = -2134; + r[306] = -3495; + q[307] = 613; + r[307] = -4049; + q[308] = -2700; + r[308] = 3079; + q[309] = 4091; + r[309] = -195; + q[310] = 3989; + r[310] = -927; + q[311] = -2385; + r[311] = 3329; + q[312] = 4094; + r[312] = -103; + q[313] = 1044; + r[313] = -3960; + q[314] = -1734; + r[314] = -3710; + q[315] = 1646; + r[315] = 3750; + q[316] = 575; + r[316] = 4055; + q[317] = -2629; + r[317] = -3140; + q[318] = 3266; + r[318] = 2471; + q[319] = 4091; + r[319] = -194; + q[320] = -2154; + r[320] = 3483; + q[321] = 659; + r[321] = 4042; + q[322] = -1785; + r[322] = -3686; + q[323] = -717; + r[323] = -4032; + q[324] = 4095; + r[324] = -37; + q[325] = -2963; + r[325] = -2827; + q[326] = -2645; + r[326] = -3126; + q[327] = 2619; + r[327] = -3148; + q[328] = 1855; + r[328] = -3651; + q[329] = -3726; + r[329] = 1699; + q[330] = -3437; + r[330] = 2227; + q[331] = 2948; + r[331] = 2842; + q[332] = -2125; + r[332] = 3501; + q[333] = -1700; + r[333] = 3726; + q[334] = 4094; + r[334] = -101; + q[335] = 2084; + r[335] = -3525; + q[336] = 3225; + r[336] = -2524; + q[337] = 2220; + r[337] = 3442; + q[338] = 3174; + r[338] = 2588; + q[339] = 229; + r[339] = -4089; + q[340] = -2381; + r[340] = -3332; + q[341] = -3677; + r[341] = -1803; + q[342] = -3191; + r[342] = -2567; + q[343] = 2465; + r[343] = 3270; + q[344] = 2681; + r[344] = -3096; + q[345] = 975; + r[345] = -3978; + q[346] = 2004; + r[346] = -3572; + q[347] = -3442; + r[347] = -2219; + q[348] = 3676; + r[348] = -1805; + q[349] = -3753; + r[349] = 1638; + q[350] = 3544; + r[350] = 2053; + q[351] = 397; + r[351] = -4076; + q[352] = 2221; + r[352] = 3440; + q[353] = -302; + r[353] = 4084; + q[354] = 4083; + r[354] = -323; + q[355] = -2253; + r[355] = -3420; + q[356] = -3038; + r[356] = 2746; + q[357] = 2884; + r[357] = 2908; + q[358] = 4070; + r[358] = 454; + q[359] = -1072; + r[359] = -3953; + q[360] = 3831; + r[360] = 1449; + q[361] = 3663; + r[361] = -1831; + q[362] = -1971; + r[362] = 3590; + q[363] = 3226; + r[363] = -2522; + q[364] = -145; + r[364] = -4093; + q[365] = 1882; + r[365] = -3637; + q[366] = 529; + r[366] = 4061; + q[367] = 2637; + r[367] = 3133; + q[368] = -4077; + r[368] = 389; + q[369] = 2156; + r[369] = -3482; + q[370] = -3276; + r[370] = 2458; + q[371] = -2687; + r[371] = -3090; + q[372] = 3469; + r[372] = -2177; + q[373] = -4093; + r[373] = -139; + q[374] = -850; + r[374] = 4006; + q[375] = -625; + r[375] = 4048; + q[376] = 1110; + r[376] = -3942; + q[377] = -3078; + r[377] = -2702; + q[378] = -2719; + r[378] = 3063; + q[379] = 742; + r[379] = 4028; + q[380] = -3902; + r[380] = -1245; + q[381] = 3888; + r[381] = -1287; + q[382] = -4081; + r[382] = 347; + q[383] = 1070; + r[383] = 3953; + q[384] = -996; + r[384] = -3972; + q[385] = 4041; + r[385] = -668; + q[386] = -2712; + r[386] = 3069; + q[387] = -3403; + r[387] = -2279; + q[388] = -3320; + r[388] = -2398; + q[389] = 3036; + r[389] = -2749; + q[390] = 1308; + r[390] = -3881; + q[391] = 2256; + r[391] = 3418; + q[392] = -1486; + r[392] = 3816; + q[393] = -2771; + r[393] = -3015; + q[394] = -3883; + r[394] = -1302; + q[395] = -3867; + r[395] = -1349; + q[396] = 3952; + r[396] = -1075; + q[397] = -789; + r[397] = 4019; + q[398] = 1458; + r[398] = 3827; + q[399] = 3832; + r[399] = -1446; + q[400] = -3001; + r[400] = -2787; + q[401] = 3463; + r[401] = 2186; + q[402] = 3606; + r[402] = 1942; + q[403] = 4023; + r[403] = 764; + q[404] = 3387; + r[404] = 2303; + q[405] = 2648; + r[405] = -3124; + q[406] = 1370; + r[406] = -3860; + q[407] = -3134; + r[407] = 2636; + q[408] = 4051; + r[408] = -600; + q[409] = -1977; + r[409] = -3587; + q[410] = 3160; + r[410] = 2605; + q[411] = 4042; + r[411] = 659; + q[412] = 3004; + r[412] = 2783; + q[413] = 3370; + r[413] = 2327; + q[414] = -419; + r[414] = -4074; + q[415] = -1968; + r[415] = 3591; + q[416] = -3705; + r[416] = -1746; + q[417] = -3331; + r[417] = -2383; + q[418] = -3634; + r[418] = 1888; + q[419] = -1981; + r[419] = -3584; + q[420] = 4069; + r[420] = -469; + q[421] = -628; + r[421] = -4047; + q[422] = -1900; + r[422] = 3628; + q[423] = 1039; + r[423] = -3961; + q[424] = 2554; + r[424] = -3201; + q[425] = -2955; + r[425] = 2836; + q[426] = 2286; + r[426] = -3398; + q[427] = -1624; + r[427] = 3760; + q[428] = 2213; + r[428] = 3446; + q[429] = -3989; + r[429] = -926; + q[430] = 192; + r[430] = -4091; + q[431] = -723; + r[431] = 4031; + q[432] = 2878; + r[432] = 2913; + q[433] = -2109; + r[433] = 3511; + q[434] = 1463; + r[434] = -3825; + q[435] = -741; + r[435] = -4028; + q[436] = -1314; + r[436] = -3879; + q[437] = 3115; + r[437] = 2659; + q[438] = -3160; + r[438] = -2605; + q[439] = 1868; + r[439] = 3644; + q[440] = -824; + r[440] = 4012; + q[441] = 781; + r[441] = 4020; + q[442] = -1257; + r[442] = -3898; + q[443] = 3331; + r[443] = -2382; + q[444] = 1642; + r[444] = -3752; + q[445] = 3748; + r[445] = -1650; + q[446] = -487; + r[446] = -4066; + q[447] = 3085; + r[447] = -2694; + q[448] = 4009; + r[448] = 839; + q[449] = -2308; + r[449] = -3383; + q[450] = 3850; + r[450] = 1397; + q[451] = -4078; + r[451] = -374; + q[452] = 2989; + r[452] = -2799; + q[453] = 3023; + r[453] = -2762; + q[454] = 1397; + r[454] = -3850; + q[455] = 323; + r[455] = 4083; + q[456] = 268; + r[456] = -4087; + q[457] = 2414; + r[457] = 3308; + q[458] = 3876; + r[458] = 1322; + q[459] = -3584; + r[459] = 1982; + q[460] = 1603; + r[460] = 3769; + q[461] = -1502; + r[461] = 3810; + q[462] = 1318; + r[462] = 3878; + q[463] = 1554; + r[463] = -3789; + q[464] = 2492; + r[464] = 3250; + q[465] = -4093; + r[465] = -154; + q[466] = 4008; + r[466] = 842; + q[467] = -2279; + r[467] = 3403; + q[468] = 3013; + r[468] = 2774; + q[469] = 2557; + r[469] = 3199; + q[470] = 4068; + r[470] = 475; + q[471] = 3324; + r[471] = -2392; + q[472] = 2653; + r[472] = -3120; + q[473] = 796; + r[473] = 4017; + q[474] = -1312; + r[474] = 3880; + q[475] = 1794; + r[475] = 3681; + q[476] = -2347; + r[476] = -3356; + q[477] = -4008; + r[477] = -840; + q[478] = -3773; + r[478] = -1592; + q[479] = 1609; + r[479] = 3766; + q[480] = -1564; + r[480] = -3785; + q[481] = 3004; + r[481] = 2784; + q[482] = 1258; + r[482] = 3897; + q[483] = 3729; + r[483] = 1693; + q[484] = -4095; + r[484] = -28; + q[485] = -4093; + r[485] = -146; + q[486] = 1393; + r[486] = -3851; + q[487] = 297; + r[487] = -4085; + q[488] = 2294; + r[488] = 3393; + q[489] = -2562; + r[489] = 3195; + q[490] = -1716; + r[490] = -3718; + q[491] = 2224; + r[491] = -3439; + q[492] = 2032; + r[492] = 3555; + q[493] = -2968; + r[493] = 2822; + q[494] = 2338; + r[494] = 3363; + q[495] = 1584; + r[495] = -3776; + q[496] = -3072; + r[496] = 2708; + q[497] = -1596; + r[497] = -3771; + q[498] = -2256; + r[498] = -3418; + q[499] = 4095; + r[499] = 89; + q[500] = -1949; + r[500] = 3602; + q[501] = 1844; + r[501] = 3657; + q[502] = -3375; + r[502] = 2319; + q[503] = -1481; + r[503] = -3818; + q[504] = 3228; + r[504] = -2520; + q[505] = 1116; + r[505] = 3940; + q[506] = -2783; + r[506] = 3004; + q[507] = 3915; + r[507] = 1201; + q[508] = 283; + r[508] = 4086; + q[509] = -3732; + r[509] = 1685; + q[510] = -433; + r[510] = -4072; + q[511] = -3667; + r[511] = 1823; + q[512] = 3883; + r[512] = 1300; + q[513] = -3742; + r[513] = 1663; + q[514] = 4093; + r[514] = -143; + q[515] = 3874; + r[515] = 1328; + q[516] = -3800; + r[516] = 1528; + q[517] = -1257; + r[517] = 3898; + q[518] = -1606; + r[518] = 3767; + q[519] = 3394; + r[519] = 2291; + q[520] = 2255; + r[520] = 3419; + q[521] = -4094; + r[521] = 120; + q[522] = -3767; + r[522] = 1606; + q[523] = 1849; + r[523] = -3654; + q[524] = -2883; + r[524] = 2908; + q[525] = 3469; + r[525] = 2176; + q[526] = 2654; + r[526] = 3119; + q[527] = -239; + r[527] = 4088; + q[528] = -651; + r[528] = 4043; + q[529] = -1140; + r[529] = 3934; + q[530] = 328; + r[530] = -4082; + q[531] = 3246; + r[531] = 2497; + q[532] = 4026; + r[532] = -753; + q[533] = -2041; + r[533] = -3550; + q[534] = -1154; + r[534] = 3929; + q[535] = -2710; + r[535] = 3070; + q[536] = -2860; + r[536] = 2932; + q[537] = 2097; + r[537] = 3517; + q[538] = 3492; + r[538] = -2140; + q[539] = 3123; + r[539] = 2649; + q[540] = 3360; + r[540] = 2342; + q[541] = 2498; + r[541] = 3245; + q[542] = 3976; + r[542] = 982; + q[543] = -2441; + r[543] = -3288; + q[544] = 3601; + r[544] = 1951; + q[545] = -4008; + r[545] = -842; + q[546] = 1243; + r[546] = 3902; + q[547] = 4069; + r[547] = 466; + q[548] = -2031; + r[548] = 3556; + q[549] = 4077; + r[549] = 386; + q[550] = -3112; + r[550] = -2663; + q[551] = 4087; + r[551] = -262; + q[552] = 4087; + r[552] = 266; + q[553] = -3907; + r[553] = -1228; + q[554] = -1611; + r[554] = 3765; + q[555] = 3066; + r[555] = -2715; + q[556] = 2657; + r[556] = 3117; + q[557] = 3912; + r[557] = -1213; + q[558] = -2531; + r[558] = -3220; + q[559] = 3500; + r[559] = -2127; + q[560] = -76; + r[560] = -4095; + q[561] = 3413; + r[561] = -2264; + q[562] = -4071; + r[562] = -448; + q[563] = 828; + r[563] = 4011; + q[564] = 3664; + r[564] = 1830; + q[565] = -1578; + r[565] = 3779; + q[566] = 3555; + r[566] = 2033; + q[567] = 3868; + r[567] = -1345; + q[568] = 4054; + r[568] = -580; + q[569] = -4094; + r[569] = 124; + q[570] = -3820; + r[570] = -1477; + q[571] = -3658; + r[571] = -1842; + q[572] = 2595; + r[572] = 3168; + q[573] = 3354; + r[573] = 2350; + q[574] = -701; + r[574] = -4035; + q[575] = -772; + r[575] = -4022; + q[576] = 2799; + r[576] = 2990; + q[577] = -3632; + r[577] = 1893; + q[578] = 310; + r[578] = 4084; + q[579] = 3984; + r[579] = -947; + q[580] = 3794; + r[580] = -1542; + q[581] = -2419; + r[581] = 3304; + q[582] = -3916; + r[582] = 1200; + q[583] = -3886; + r[583] = 1292; + q[584] = -3299; + r[584] = 2426; + q[585] = -437; + r[585] = 4072; + q[586] = 2053; + r[586] = -3544; + q[587] = 3987; + r[587] = 937; + q[588] = -789; + r[588] = -4019; + q[589] = 4055; + r[589] = -575; + q[590] = -3894; + r[590] = 1270; + q[591] = 4003; + r[591] = -864; + q[592] = -3060; + r[592] = 2721; + q[593] = -4009; + r[593] = 836; + q[594] = -1655; + r[594] = -3746; + q[595] = 3954; + r[595] = -1067; + q[596] = -773; + r[596] = 4022; + q[597] = -422; + r[597] = 4074; + q[598] = -3384; + r[598] = 2306; + q[599] = 195; + r[599] = -4091; + q[600] = -298; + r[600] = 4085; + q[601] = -3988; + r[601] = 931; + q[602] = 2014; + r[602] = -3566; + q[603] = 3349; + r[603] = -2357; + q[604] = 3800; + r[604] = 1526; + q[605] = 3858; + r[605] = 1374; + q[606] = 2947; + r[606] = 2844; + q[607] = -1483; + r[607] = -3818; + q[608] = 4056; + r[608] = -565; + q[609] = 2612; + r[609] = -3154; + q[610] = 2326; + r[610] = 3371; + q[611] = -3545; + r[611] = 2051; + q[612] = -1001; + r[612] = -3971; + q[613] = 3211; + r[613] = 2541; + q[614] = -2717; + r[614] = 3065; + q[615] = -3159; + r[615] = -2606; + q[616] = 2869; + r[616] = -2922; + q[617] = -1290; + r[617] = -3887; + q[618] = 2479; + r[618] = 3260; + q[619] = 3420; + r[619] = 2252; + q[620] = 1823; + r[620] = 3667; + q[621] = 3368; + r[621] = 2330; + q[622] = -3819; + r[622] = -1480; + q[623] = 3800; + r[623] = 1528; + q[624] = 3773; + r[624] = 1594; + q[625] = -189; + r[625] = -4091; + q[626] = -4067; + r[626] = -485; + q[627] = 2277; + r[627] = -3404; + q[628] = -4089; + r[628] = -233; + q[629] = -3634; + r[629] = 1889; + q[630] = 3292; + r[630] = 2437; + q[631] = -530; + r[631] = 4061; + q[632] = -3109; + r[632] = 2666; + q[633] = -3741; + r[633] = 1667; + q[634] = -1903; + r[634] = -3626; + q[635] = 3879; + r[635] = -1315; + q[636] = 4083; + r[636] = -315; + q[637] = -1148; + r[637] = 3931; + q[638] = 2630; + r[638] = 3139; + q[639] = -4001; + r[639] = 876; + q[640] = -2295; + r[640] = -3392; + q[641] = 1090; + r[641] = -3948; + q[642] = -3024; + r[642] = 2762; + q[643] = 2728; + r[643] = -3054; + q[644] = -3305; + r[644] = 2419; + q[645] = 60; + r[645] = 4095; + q[646] = 4048; + r[646] = -620; + q[647] = 589; + r[647] = -4053; + q[648] = -3867; + r[648] = 1347; + q[649] = -2944; + r[649] = -2847; + q[650] = -2721; + r[650] = 3060; + q[651] = 2928; + r[651] = 2863; + q[652] = 801; + r[652] = 4016; + q[653] = -3644; + r[653] = 1870; + q[654] = -1648; + r[654] = -3749; + q[655] = 825; + r[655] = -4012; + q[656] = -2036; + r[656] = -3553; + q[657] = -1192; + r[657] = -3918; + q[658] = 2875; + r[658] = 2916; + q[659] = -1831; + r[659] = -3663; + q[660] = -2865; + r[660] = -2926; + q[661] = -575; + r[661] = -4055; + q[662] = -3870; + r[662] = 1340; + q[663] = -4080; + r[663] = -356; + q[664] = -2176; + r[664] = -3469; + q[665] = -2986; + r[665] = -2803; + q[666] = 3978; + r[666] = -972; + q[667] = 2437; + r[667] = 3291; + q[668] = -3528; + r[668] = 2080; + q[669] = -3300; + r[669] = -2425; + q[670] = 3085; + r[670] = 2693; + q[671] = -3700; + r[671] = -1756; + q[672] = 3216; + r[672] = -2535; + q[673] = 4094; + r[673] = -91; + q[674] = 3775; + r[674] = -1589; + q[675] = 1097; + r[675] = -3946; + q[676] = -152; + r[676] = -4093; + q[677] = -3490; + r[677] = 2142; + q[678] = 3747; + r[678] = 1654; + q[679] = -1490; + r[679] = -3815; + q[680] = -3998; + r[680] = -886; + q[681] = 3726; + r[681] = -1700; + q[682] = -1600; + r[682] = 3770; + q[683] = -87; + r[683] = 4095; + q[684] = 2538; + r[684] = -3214; + q[685] = -4095; + r[685] = 52; + q[686] = -3993; + r[686] = -910; + q[687] = 4051; + r[687] = 603; + q[688] = -1242; + r[688] = -3902; + q[689] = 2155; + r[689] = 3482; + q[690] = 1270; + r[690] = 3893; + q[691] = 1919; + r[691] = -3618; + q[692] = -3145; + r[692] = 2623; + q[693] = 2475; + r[693] = 3263; + q[694] = 2226; + r[694] = -3437; + q[695] = -3894; + r[695] = -1269; + q[696] = -429; + r[696] = 4073; + q[697] = -1346; + r[697] = 3868; + q[698] = 1297; + r[698] = 3885; + q[699] = 1699; + r[699] = 3726; + q[700] = -3375; + r[700] = 2319; + q[701] = 1577; + r[701] = -3779; + q[702] = -63; + r[702] = 4095; + q[703] = 1215; + r[703] = -3911; + q[704] = -1492; + r[704] = 3814; + q[705] = -1530; + r[705] = -3799; + q[706] = 3442; + r[706] = 2218; + q[707] = -3867; + r[707] = -1349; + q[708] = -3291; + r[708] = -2437; + q[709] = -2253; + r[709] = -3420; + q[710] = -150; + r[710] = -4093; + q[711] = -2686; + r[711] = -3092; + q[712] = 3470; + r[712] = 2175; + q[713] = -3826; + r[713] = -1461; + q[714] = -3148; + r[714] = 2619; + q[715] = -3858; + r[715] = 1375; + q[716] = -3844; + r[716] = -1412; + q[717] = -3652; + r[717] = 1854; + q[718] = 4018; + r[718] = -791; + q[719] = 179; + r[719] = -4092; + q[720] = 3498; + r[720] = 2129; + q[721] = -1999; + r[721] = -3574; + q[722] = 3531; + r[722] = 2075; + q[723] = 4050; + r[723] = -606; + q[724] = -1639; + r[724] = 3753; + q[725] = -3661; + r[725] = 1835; + q[726] = 4039; + r[726] = 679; + q[727] = 3561; + r[727] = 2023; + q[728] = 528; + r[728] = 4061; + q[729] = -634; + r[729] = -4046; + q[730] = 364; + r[730] = -4079; + q[731] = 2735; + r[731] = 3048; + q[732] = 3978; + r[732] = 973; + q[733] = -4073; + r[733] = -427; + q[734] = -3722; + r[734] = 1708; + q[735] = 2356; + r[735] = -3350; + q[736] = -1125; + r[736] = -3938; + q[737] = 4054; + r[737] = 580; + q[738] = 3328; + r[738] = -2387; + q[739] = 1439; + r[739] = -3834; + q[740] = 1746; + r[740] = 3705; + q[741] = 2507; + r[741] = 3238; + q[742] = 3839; + r[742] = -1427; + q[743] = 488; + r[743] = -4066; + q[744] = 1187; + r[744] = 3920; + q[745] = 2038; + r[745] = -3552; + q[746] = -905; + r[746] = -3994; + q[747] = -236; + r[747] = 4089; + q[748] = 208; + r[748] = -4090; + q[749] = 1660; + r[749] = 3744; + q[750] = -4074; + r[750] = -415; + q[751] = -2304; + r[751] = 3385; + q[752] = -2457; + r[752] = 3276; + q[753] = 3302; + r[753] = 2423; + q[754] = 1778; + r[754] = -3689; + q[755] = 2019; + r[755] = 3563; + q[756] = 4037; + r[756] = 687; + q[757] = -2365; + r[757] = 3343; + q[758] = 5; + r[758] = -4095; + q[759] = 160; + r[759] = -4092; + +} /*initRand*/ + +/** + * initializes the MEL-2_LINEAR LOOKUP TABLE + * @param sig_inObj : sig PU internal object of the sub-object + * @return void + * @remarks translated from matlab code to c-code + * @callgraph + * @callergraph + * + * input + * - bilinTab : base address of bilinTable destination vector + * - alpha : warping factor + * - size : size of the vectors to be generated + * - A,B : base address of array of indexes for lookup table implementation + * - D : base address of delta array for lookup table implementation + * + * output + * - bilinTab, A, B, D : initialized vectors + */ +void mel_2_lin_init(sig_innerobj_t *sig_inObj) +{ + + /*Declare variables tied to I/O PARAMS formerly passed by value or reference*/ + picoos_single alpha; + picoos_int32 *D; + picoos_int32 size; + picoos_int16 *A; + + /*Link local variables with sig data object*/ + + alpha = sig_inObj->warp_p; + size = (sig_inObj->hfftsize_p) + 1; + A = sig_inObj->A_p; + D = sig_inObj->d_p; + /* + fixed point interpolation tables + scaling factor: 0x20 + corresponding bit shift: 5 + */ + + A[0] = 0; + D[0] = 0; + A[1] = 2; + D[1] = 14; + A[2] = 4; + D[2] = 29; + A[3] = 7; + D[3] = 11; + A[4] = 9; + D[4] = 24; + A[5] = 12; + D[5] = 5; + A[6] = 14; + D[6] = 18; + A[7] = 16; + D[7] = 30; + A[8] = 19; + D[8] = 9; + A[9] = 21; + D[9] = 19; + A[10] = 23; + D[10] = 29; + A[11] = 26; + D[11] = 5; + A[12] = 28; + D[12] = 12; + A[13] = 30; + D[13] = 19; + A[14] = 32; + D[14] = 24; + A[15] = 34; + D[15] = 27; + A[16] = 36; + D[16] = 30; + A[17] = 38; + D[17] = 31; + A[18] = 40; + D[18] = 31; + A[19] = 42; + D[19] = 29; + A[20] = 44; + D[20] = 26; + A[21] = 46; + D[21] = 22; + A[22] = 48; + D[22] = 17; + A[23] = 50; + D[23] = 10; + A[24] = 52; + D[24] = 2; + A[25] = 53; + D[25] = 24; + A[26] = 55; + D[26] = 13; + A[27] = 57; + D[27] = 1; + A[28] = 58; + D[28] = 20; + A[29] = 60; + D[29] = 5; + A[30] = 61; + D[30] = 21; + A[31] = 63; + D[31] = 4; + A[32] = 64; + D[32] = 18; + A[33] = 65; + D[33] = 31; + A[34] = 67; + D[34] = 11; + A[35] = 68; + D[35] = 21; + A[36] = 69; + D[36] = 31; + A[37] = 71; + D[37] = 7; + A[38] = 72; + D[38] = 14; + A[39] = 73; + D[39] = 21; + A[40] = 74; + D[40] = 27; + A[41] = 75; + D[41] = 31; + A[42] = 77; + D[42] = 3; + A[43] = 78; + D[43] = 6; + A[44] = 79; + D[44] = 8; + A[45] = 80; + D[45] = 10; + A[46] = 81; + D[46] = 10; + A[47] = 82; + D[47] = 10; + A[48] = 83; + D[48] = 9; + A[49] = 84; + D[49] = 8; + A[50] = 85; + D[50] = 6; + A[51] = 86; + D[51] = 3; + A[52] = 86; + D[52] = 31; + A[53] = 87; + D[53] = 27; + A[54] = 88; + D[54] = 23; + A[55] = 89; + D[55] = 18; + A[56] = 90; + D[56] = 12; + A[57] = 91; + D[57] = 6; + A[58] = 91; + D[58] = 31; + A[59] = 92; + D[59] = 24; + A[60] = 93; + D[60] = 16; + A[61] = 94; + D[61] = 8; + A[62] = 94; + D[62] = 31; + A[63] = 95; + D[63] = 22; + A[64] = 96; + D[64] = 13; + A[65] = 97; + D[65] = 3; + A[66] = 97; + D[66] = 25; + A[67] = 98; + D[67] = 14; + A[68] = 99; + D[68] = 3; + A[69] = 99; + D[69] = 24; + A[70] = 100; + D[70] = 13; + A[71] = 101; + D[71] = 1; + A[72] = 101; + D[72] = 21; + A[73] = 102; + D[73] = 8; + A[74] = 102; + D[74] = 27; + A[75] = 103; + D[75] = 14; + A[76] = 104; + D[76] = 1; + A[77] = 104; + D[77] = 19; + A[78] = 105; + D[78] = 6; + A[79] = 105; + D[79] = 24; + A[80] = 106; + D[80] = 9; + A[81] = 106; + D[81] = 27; + A[82] = 107; + D[82] = 12; + A[83] = 107; + D[83] = 29; + A[84] = 108; + D[84] = 14; + A[85] = 108; + D[85] = 31; + A[86] = 109; + D[86] = 15; + A[87] = 109; + D[87] = 31; + A[88] = 110; + D[88] = 16; + A[89] = 110; + D[89] = 31; + A[90] = 111; + D[90] = 15; + A[91] = 111; + D[91] = 31; + A[92] = 112; + D[92] = 14; + A[93] = 112; + D[93] = 30; + A[94] = 113; + D[94] = 13; + A[95] = 113; + D[95] = 28; + A[96] = 114; + D[96] = 11; + A[97] = 114; + D[97] = 26; + A[98] = 115; + D[98] = 9; + A[99] = 115; + D[99] = 23; + A[100] = 116; + D[100] = 6; + A[101] = 116; + D[101] = 20; + A[102] = 117; + D[102] = 2; + A[103] = 117; + D[103] = 16; + A[104] = 117; + D[104] = 31; + A[105] = 118; + D[105] = 13; + A[106] = 118; + D[106] = 27; + A[107] = 119; + D[107] = 8; + A[108] = 119; + D[108] = 22; + A[109] = 120; + D[109] = 4; + A[110] = 120; + D[110] = 17; + A[111] = 120; + D[111] = 31; + A[112] = 121; + D[112] = 13; + A[113] = 121; + D[113] = 26; + A[114] = 122; + D[114] = 8; + A[115] = 122; + D[115] = 21; + A[116] = 123; + D[116] = 2; + A[117] = 123; + D[117] = 15; + A[118] = 123; + D[118] = 29; + A[119] = 124; + D[119] = 10; + A[120] = 124; + D[120] = 23; + A[121] = 125; + D[121] = 4; + A[122] = 125; + D[122] = 17; + A[123] = 125; + D[123] = 31; + A[124] = 126; + D[124] = 12; + A[125] = 126; + D[125] = 25; + A[126] = 127; + D[126] = 6; + A[127] = 127; + D[127] = 19; + A[128] = 128; + D[128] = 0; + +}/*mel_2_lin_init*/ + +/** + * function to be documented + * @param ang : ?? + * @param table : ?? + * @param cs : ?? + * @param sn : ?? + * @return void + * @callgraph + * @callergraph + */ +static void get_trig(picoos_int32 ang, picoos_int32 *table, picoos_int32 *cs, + picoos_int32 *sn) +{ + picoos_int32 i, j, k; + + i = k = ang >> PICODSP_PI_SHIFT; /* * PICODSP_COS_TABLE_LEN2/PICODSP_FIX_SCALE2 */ + if (i < 0) + i = -i; + j = 1; + i &= (PICODSP_COS_TABLE_LEN4 - 1); + if (i > PICODSP_COS_TABLE_LEN2) + i = PICODSP_COS_TABLE_LEN4 - i; + if (i > PICODSP_COS_TABLE_LEN) { + j = -1; + i = PICODSP_COS_TABLE_LEN2 - i; + } + if (j == 1) + *cs = table[i]; + else + *cs = -table[i]; + + i = k - PICODSP_COS_TABLE_LEN; + if (i < 0) + i = -i; + j = 1; + i &= (PICODSP_COS_TABLE_LEN4 - 1); + if (i > PICODSP_COS_TABLE_LEN2) + i = PICODSP_COS_TABLE_LEN4 - i; + if (i > PICODSP_COS_TABLE_LEN) { + j = -1; + i = PICODSP_COS_TABLE_LEN2 - i; + } + if (j == 1) + *sn = table[i]; + else + *sn = -table[i]; +}/*get_trig*/ + +/** + * function to be documented + * @param sig_inObj : sig PU internal object of the sub-object + * @return void + * @callgraph + * @callergraph + */ +void save_transition_frame(sig_innerobj_t *sig_inObj) +{ + picoos_int32 *tmp, *tmp2; /*for loop unrolling*/ + + if (sig_inObj->voiced_p != sig_inObj->prevVoiced_p) { + sig_inObj->VoicTrans = sig_inObj->prevVoiced_p; /*remember last voicing transition*/ + tmp = sig_inObj->ImpResp_p; + tmp2 = sig_inObj->imp_p; + FAST_DEVICE(PICODSP_FFTSIZE,*(tmp++)=*(tmp2++);); + if (sig_inObj->voiced_p == 1) + sig_inObj->nV = 0; + else + sig_inObj->nU = 0; /*to avoid problems in case of very short voiced or unvoiced parts (less than 4 frames long)*/ + } +}/*save_transition_frame*/ + +/** + * calculates an unweighted excitation window + * @param sig_inObj : sig PU internal object of the sub-object + * @param nextPeak : position of next peak (excitation position) + * @return PICO_OK + * @callgraph + * @callergraph + * input + * - hop : hop size in samples + * - winlen : excitation window length + * - E : energy + * - F0 : pitch + * - nextPeak : state that remembers next excitation index + * - Fs - sampling frequency + * output + * - LocV, LocU : (MAX_EN size) location of excitation points + * - EnV, EnU : (MAX_EN size) RMS values of excitation (scaled) + * - nV, nU : (integers) number of excitation points + * - nextPeak new position of lastPeak to calculate next frame + */ +static void get_simple_excitation(sig_innerobj_t *sig_inObj, + picoos_int16 *nextPeak) +{ + /*Define local variables*/ + picoos_int16 nI, nJ, k; + /* picoos_single InvSqrt3=(picoos_single)2/(picoos_single)sqrt(3.0); *//*constant*/ + picoos_int32 Ti, sqrtTi; + picoos_int16 hop, winlen, Fs; + picoos_single E, F0; + picoos_int16 voiced; + picoos_single fact; /*normalization factor*/ + picoos_single rounding = 0.5f; + + /*Link local variables to sig object*/ + hop = sig_inObj->hop_p; + winlen = sig_inObj->m2_p; + Fs = sig_inObj->Fs_p; + E = sig_inObj->E_p; + F0 = sig_inObj->F0_p; + voiced = sig_inObj->voiced_p; + + E = (E > 5) ? 9 : (E > 1) ? 2 * E - 1 : E; + + + /* shift previous excitation window by hop samples*/ + for (nI = 0; nI < sig_inObj->nV; nI++) { + sig_inObj->LocV[nI] = sig_inObj->LocV[nI] - hop; + } + for (nI = 0; nI < sig_inObj->nU; nI++) { + sig_inObj->LocU[nI] = sig_inObj->LocU[nI] - hop; + } + + /*get rid of the voiced points that fall out of the interval*/ + nI = 0; + while ((sig_inObj->LocV[nI] < 0) && nI < sig_inObj->nV) + nI++; + + for (nJ = nI; nJ < sig_inObj->nV; nJ++) { + sig_inObj->LocV[nJ - nI] = sig_inObj->LocV[nJ]; + sig_inObj->EnV[nJ - nI] = sig_inObj->EnV[nJ]; + } + sig_inObj->nV -= nI; + /*get rid of the unvoiced points that fall out of the interval */ + nI = 0; + while ((sig_inObj->LocU[nI] < 0) && nI < sig_inObj->nU) + nI++; + + for (nJ = nI; nJ < sig_inObj->nU; nJ++) { + sig_inObj->LocU[nJ - nI] = sig_inObj->LocU[nJ]; + sig_inObj->EnU[nJ - nI] = sig_inObj->EnU[nJ]; + } + sig_inObj->nU -= nI; + + *nextPeak -= hop; + k = *nextPeak; + + fact = 3; + if (voiced == 0) { /*Unvoiced*/ + + Ti = (picoos_int32) (rounding + (picoos_single) Fs + / (picoos_single) sig_inObj->Fuv_p); /* round Period*/ + sqrtTi = (picoos_int32) (E * sqrt((double) Fs + / (hop * sig_inObj->Fuv_p)) * fact * PICODSP_GETEXC_K1); + while (k < winlen) { + if (k < winlen) { + sig_inObj->LocU[sig_inObj->nU] = k; + sig_inObj->EnU[sig_inObj->nU] = sqrtTi; + sig_inObj->nU++; + k += (picoos_int16) Ti; + } + } + } else { /*Voiced*/ + Ti + = (picoos_int32) (rounding + (picoos_single) Fs + / (picoos_single) F0); /*Period*/ + sqrtTi = (picoos_int32) (E + * sqrt((double) Fs / (hop * sig_inObj->F0_p)) * fact + * PICODSP_GETEXC_K1); + while (k < winlen) { + sig_inObj->LocV[sig_inObj->nV] = k; + sig_inObj->EnV[sig_inObj->nV] = sqrtTi; + sig_inObj->nV++; + k += (picoos_int16) Ti; + } + } + *nextPeak = k; + +}/*get_simple_excitation*/ + +#ifdef __cplusplus +} +#endif + +/* end picosig2.c */ diff --git a/pico/lib/picosig2.h b/pico/lib/picosig2.h new file mode 100644 index 0000000..e2577ff --- /dev/null +++ b/pico/lib/picosig2.h @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picosig2.h + * + * Signal Generation PU - Internal functions - header file + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#ifndef PICOSIG2_H_ +#define PICOSIG2_H_ + +#include "picoos.h" +#include "picodsp.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +/*---------------------------------------------------------- + // Name : sig_innerobj + // Function: innerobject definition for the sig processing + // Shortcut: sig + //---------------------------------------------------------*/ +typedef struct sig_innerobj +{ + + /*-----------------------Definition of the local storage for this PU--------*/ + picoos_int16 *idx_vect1; /*reserved for bit reversal tables*/ + picoos_int16 *idx_vect2; /*reserved for table lookup "A" vector*/ + picoos_int16 *idx_vect4; /*reserved for max peak index arrax in pchip*/ + picoos_int16 *idx_vect5; /*reserved for min index arrax in sigana_singleIMF*/ + picoos_int16 *idx_vect6; /*reserved for max index arrax in sigana_singleIMF*/ + picoos_int16 *idx_vect7; /*reserved for dispersed phase */ + picoos_int16 *idx_vect8; /*reserved for LocV*/ + picoos_int16 *idx_vect9; /*reserved for LocU*/ + + picoos_int32 *int_vec22; /*reserved for normalized hanning window - fixed point */ + picoos_int32 *int_vec23; /*reserved for impresp - fixed point */ + picoos_int32 *int_vec24; /*reserved for impresp - fixed point */ + picoos_int32 *int_vec25; /*reserved for window - fixed point */ + picoos_int32 *int_vec26; /*reserved for wavBuf - fixed point */ + picoos_int32 *int_vec28; /*reserved for cepstral vectors input - fixed point */ + picoos_int32 *int_vec29; /*reserved for cepstral vectors input - fixed point */ + picoos_int32 *int_vec38; /*reserved for cepstral vectors input - fixed point */ + picoos_int32 *int_vec30; /*reserved for cepstral vectors input - fixed point */ + picoos_int32 *int_vec31; /*reserved for cepstral vectors input - fixed point */ + + picoos_int32 *int_vec32; /*reserved for cepstral vectors input - fixed point */ + picoos_int32 *int_vec33; /*reserved for cepstral vectors input - fixed point */ + + picoos_int32 *int_vec34; /* reserved for sin table- fixed point */ + picoos_int32 *int_vec35; /* reserved for cos table - fixed point */ + picoos_int32 *int_vec36; /* reserved for currently used sin table- fixed point */ + picoos_int32 *int_vec37; /* reserved for currently used cos table - fixed point */ + + picoos_int32 *int_vec39; /* reserved for ang - fixed point */ + picoos_int32 *int_vec40; /* reserved for cos table - fixed point */ + + picoos_int32 *int_vec41[CEPST_BUFF_SIZE]; /*reserved for phase smoothing - cepstrum buffers */ + picoos_int32 *int_vec42[PHASE_BUFF_SIZE]; /*reserved for phase smoothing - phase buffers */ + + picoos_int16 idx_vect10[CEPST_BUFF_SIZE]; /*reserved for pitch value buffering before phase smoothing*/ + picoos_int16 idx_vect11[CEPST_BUFF_SIZE]; /*reserved for phonetic value bufferingid before phase smoothing*/ + picoos_int16 idx_vect12[CEPST_BUFF_SIZE]; /*reserved for voicing value bufferingbefore phase smoothing*/ + picoos_int16 idx_vect13[CEPST_BUFF_SIZE]; /*reserved for unrectified pitch value bufferingbefore phase smoothing*/ + picoos_int16 idx_vect14[PHASE_BUFF_SIZE]; /*reserved for vox_bnd value buffering before phase smoothing*/ + + picoos_int32 *sig_vec1; + + picoos_single bvalue1; /*reserved for warp*/ + picoos_int32 ibvalue2; /*reserved for voxbnd*/ + picoos_int32 ibvalue3; /*reserved for voxbnd2*/ + picoos_single bvalue4; /*reserved for E*/ + picoos_single bvalue5; /*reserved for F0*/ + picoos_single bvalue6; /*reserved for sMod*/ + + picoos_single bvalue7; /*reserved for voicing*/ + picoos_single bvalue8; /*reserved for unrectified pitch*/ + + picoos_int16 ivalue1; /*reserved for m1,ceporder*/ + picoos_int16 ivalue2; /*reserved for m2,fftorder,windowlen*/ + picoos_int16 ivalue3; /*reserved for fftorder/2*/ + picoos_int16 ivalue4; /*reserved for framelen, displacement*/ + picoos_int16 ivalue5; /*reserved for voiced*/ + picoos_int16 ivalue6; /*reserved for generic result code*/ + picoos_int16 ivalue7; /*reserved for i*/ + picoos_int16 ivalue8; /*reserved for j*/ + picoos_int16 ivalue9; /*reserved for hop*/ + picoos_int16 ivalue10; /*reserved for nextPeak*/ + picoos_int16 ivalue11; /*reserved for nFrame*/ + picoos_int16 ivalue12; /*reserved for raw*/ + picoos_int16 ivalue13; /*reserved for hts engine flag*/ + picoos_int16 ivalue14; /*reserved for ph id*/ + picoos_int16 ivalue15; /*reserved for Voiced*/ + picoos_int16 ivalue16; /*reserved for prevVoiced*/ + picoos_int16 ivalue17; /*reserved for nV (size of LocV)*/ + picoos_int16 ivalue18; /*reserved for nU (size of LocU)*/ + + picoos_int16 ivalue19; /*reserved for voicTrans*/ + + picoos_int16 ivalue20; /*reserved for n_availabe index*/ + + picoos_int32 lvalue1; /*reserved for sampling rate*/ + picoos_int32 lvalue2; /*reserved for VCutoff*/ + picoos_int32 lvalue3; /*reserved for UVCutoff*/ + picoos_int32 lvalue4; /*reserved for fMax */ + + picoos_int32 iRand; /*reserved for phase random table poointer ())*/ + +} sig_innerobj_t; + +/*------------------------------------------------------------------ + Exported (to picosig.c) Service routines : + routine name and I/O parameters are to be maintained for PICO compatibility!! + ------------------------------------------------------------------*/ +extern pico_status_t sigAllocate(picoos_MemoryManager mm, + sig_innerobj_t *sig_inObj); +extern void sigDeallocate(picoos_MemoryManager mm, sig_innerobj_t *sig_inObj); +extern void sigDspInitialize(sig_innerobj_t *sig_inObj, picoos_int32 resetMode); + +/*------------------------------------------------------------------ + Exported (to picosig.c) Processing routines : + routine number, name and content can be changed. unique I/O parameter should be "sig" + ------------------------------------------------------------------*/ +extern void mel_2_lin_init(sig_innerobj_t *sig_inObj); +extern void save_transition_frame(sig_innerobj_t *sig_inObj); +extern void mel_2_lin_init(sig_innerobj_t *sig_inObj); +extern void post_filter_init(sig_innerobj_t *sig_inObj); +extern void mel_2_lin_lookup(sig_innerobj_t *sig_inObj, picoos_uint32 mgc); +extern void post_filter(sig_innerobj_t *sig_inObj); +extern void phase_spec2(sig_innerobj_t *sig_inObj); +extern void env_spec(sig_innerobj_t *sig_inObj); +extern void save_transition_frame(sig_innerobj_t *sig_inObj); +extern void td_psola2(sig_innerobj_t *sig_inObj); +extern void impulse_response(sig_innerobj_t *sig_inObj); +extern void overlap_add(sig_innerobj_t *sig_inObj); + +/* ------------------------------------------------------------------- + * symbolic vs area assignements + * -------------------------------------------------------------------*/ +#define WavBuff_p int_vec26 /*output is Wav buffer (2*FFTSize)*/ +#define window_p int_vec25 /*window function (hanning) */ +#define ImpResp_p int_vec23 /*output step 6*/ +#define imp_p int_vec24 /*output step 6*/ +#define warp_p bvalue1 /*warp factor */ +#define voxbnd_p ibvalue2 /*phase spectra reconstruction noise factor V*/ /* fixed point */ +#define voxbnd2_p ibvalue3 /*phase spectra reconstruction noise factor UV */ /* fixed point */ +#define E_p bvalue4 /*energy after Envelope spectrum calculation */ +#define F0_p bvalue5 /*pitch*/ +#define sMod_p bvalue6 /*speaker modification factor*/ +#define voicing bvalue7 /*voicing*/ +#define Fuv_p bvalue8 /*unrectified pitch (for unvoiced too)*/ +#define m1_p ivalue1 /*ceporder(melorder=ceporder-1) */ +#define m2_p ivalue2 /*fftorder*/ +#define windowLen_p ivalue2 /*same as fftorder*/ +#define hfftsize_p ivalue3 /*fftorder/2*/ +#define framesz_p ivalue4 /*displacement*/ +#define voiced_p ivalue5 /*voicing state*/ +#define nRes_p ivalue6 /*generic result*/ +#define i_p ivalue7 /*generic counter*/ +#define j_p ivalue8 /*generic counter*/ +#define hop_p ivalue9 /*hop */ +#define nextPeak_p ivalue10 /*nextPeak*/ +#define phId_p ivalue14 /*phonetic id*/ +#define prevVoiced_p ivalue16 /*previous voicing state (for frame 1)*/ +#define nV ivalue17 +#define nU ivalue18 +#define VoicTrans ivalue19 /* */ +#define Fs_p lvalue1 /*Sampling frequency*/ +#define VCutoff_p lvalue2 /*voicing cut off frequency in Hz*/ +#define UVCutoff_p lvalue3 /*unvoicing cut off frequency in Hz*/ +/* Reusable area */ +#define wcep_pI int_vec28 /*input step1*/ +#define d_p int_vec38 /*output mel_2_lin_init : table lookup vector D*/ +#define A_p idx_vect2 /*output mel_2_lin_init : table lookup vector A*/ +#define ang_p int_vec39 /*output step4*/ +#define EnV int_vec30 +#define EnU int_vec31 +#define randCosTbl int_vec34 +#define randSinTbl int_vec35 +#define outCosTbl int_vec36 +#define outSinTbl int_vec37 +#define cos_table int_vec40 +#define norm_window_p int_vec22 /*window function (hanning) */ +#define norm_window2_p int_vec27 /*window function (hanning) */ +#define F2r_p int_vec32 /*output step 7*/ +#define F2i_p int_vec33 /*output step 7*/ +#define LocV idx_vect8 /*excitation position voiced pulses*/ +#define LocU idx_vect9 /*excitation position unvoiced pulses*/ + +#define CepBuff int_vec41 /*Buffer for incoming cepstral vector pointers*/ +#define PhsBuff int_vec42 /*Buffer for incoming phase vector pointers*/ +#define F0Buff idx_vect10 /*Buffer for incoming F0 values*/ +#define PhIdBuff idx_vect11 /*Buffer for incoming PhId values*/ +#define VoicingBuff idx_vect12 /*Buffer for incoming voicing values*/ +#define FuVBuff idx_vect13 /*Buffer for incoming FuV values*/ +#define VoxBndBuff idx_vect14 /*Buffer for incoming VoxBnd values*/ + +#define n_available ivalue20 /*variable for indexing the incoming buffers*/ + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pico/lib/picospho.c b/pico/lib/picospho.c new file mode 100644 index 0000000..577d047 --- /dev/null +++ b/pico/lib/picospho.c @@ -0,0 +1,1694 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picospho.c + * + * sentence phonemic/phonetic FSTs PU + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include "picoos.h" +#include "picodbg.h" +#include "picodata.h" + +#include "picoknow.h" +#include "picokfst.h" +#include "picoktab.h" +#include "picotrns.h" + +#include "picospho.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +#define SPHO_BUFSIZE (3 * PICODATA_BUFSIZE_DEFAULT) + + + +#define SPHO_MAX_ALTDESC_SIZE (60 * PICOTRNS_MAX_NUM_POSSYM) + + +#define SPHO_SMALLEST_SIL_DUR 1 + + +/** @addtogroup picospho + * + * Algorithmic description + * ======================= + * The main function, sphoStep, is divided into the subprocesses (processing states) described further down. + * + * Flow control: + * ------------ + * The processing flow is controlled by setting + * - 'procState' : the next state to be processed + * - 'feedFollowState' : the state to be processed after the feed state (the feed state is treated like a primitive "subroutine") + * - some other flags + * + * Buffering: + * --------- + * - The input items are mainly stored and processed in two buffers, collectively called 'inBuf' + * - cbuf : unstructured buffer containing item contents + * - headx : structured buffer containing item heads, each expanded by a pointer to the item contents + * and space for a boundary potentially to be inserted (to the left of the original item) + * - For transduction, phonemes and their position are extracted from inBuf into + * - phonBuf, + * processed there, and the resulting phonemes realigned with inBuf. + * - Word items are split into syllables, stored in + * - sylBuf + * - Items to be output are stored in outBuf + * + * Windowing: + * --------- + * Optimal solutions are achieved if a whole sentence is processed at once. However, if any of the buffers are too small, + * only sentence parts are processed. To improve the quality of such sub-optimal solutions, a moving-window-with-overlap is applied: + * - [0,headxReadPos[ : the window considered for transduction + * - [activeStartPos,activeEndPos[ : the "active" subrange of the window actually used for output + * - penultima : the position (within the active range) that should be used as new window start when shifting the window + * + * After PROCESS_PARSE: + * 0 activeStartPos penultima activeEndPos headxReadPos headxWritePos + * | | | | | | + * |-------------=================================---------------| ['----': context '====' : active subrange) + * + * After PROCESS_SHIFT: + * 0 activeStartPos headWritePos + * | | | | + * |------------... (only left context is known; new active range, penultima, and right context to be established at next parse) + * + * Processing states: + * ----------------- + * - INIT : initialize state variables + * - COLLECT : collect items into internal buffers ("inBuf") + * - PROCESS_PARSE : go through inBuf items and extract position/phoneme pairs into phoneme buffer 'phonBuf' + * word boundary phonemes are inserted between words + * - PROCESS_TRANSDUCE : transduce phonBuf + * - PROCESS_BOUNDS : go through inBuf items again and match against transduced pos/phoneme + * this is the first round of alignment, only inserting/deleting/modifying bounds, according to + * - existing BOUND items + * - newly produced word bounds separating WORDPHON items + * - bound upgrades/downgrades from transduction + * - bound upgrades/downgrades/insertions from SIL command items (originating e.g. from text commands) + * all relevant bounds are placed in the corresponding headx extention; original bound items become invalid. + * - PROCESS_RECOMB : go through inBuf items again and match against transduced pos/phoneme + * this is the second round of alignment, treating non-BOUND items + * - WORDPHONs are broken into syllables by "calling" PROCESS_SYL + * - "side-bounds" (in the headx extension) are output by "calling" FEED + * - BOUND items are consumed with no effect + * - other items are output unchanged "calling" FEED + * - PROCESS_SYL : the WORDPHON coming from RECOMB is matched against the phonBuf and (new) SYLLPHON items + * are created. (the original wordphon is consumed) + * - FEED : feeds one item and returns to spho->feedFollowState + * - SHIFT : items in inBuf are shifted left to make room for new items. If a sentence doesn't fit + * inBuf in its entirety, left and/or right contexts are kept so they can be considered in + * the next transduction. + */ + + + +/* PU sphoStep states */ +#define SPHO_STEPSTATE_INIT 0 +#define SPHO_STEPSTATE_COLLECT 1 +#define SPHO_STEPSTATE_PROCESS_PARSE 2 +#define SPHO_STEPSTATE_PROCESS_TRANSDUCE 3 +#define SPHO_STEPSTATE_PROCESS_BOUNDS 4 +#define SPHO_STEPSTATE_PROCESS_RECOMB 5 +#define SPHO_STEPSTATE_PROCESS_SYL 6 +#define SPHO_STEPSTATE_FEED 7 +#define SPHO_STEPSTATE_SHIFT 8 + +#define SPHO_POS_INVALID (PICOTRNS_POS_INVALID) /* indicates that no position was set yet */ + +/* nr item restriction: maximum number of extended item heads in headx */ +#define SPHO_MAXNR_HEADX 60 + +/* nr item restriction: maximum size of all item contents together in cont */ +#define SPHO_MAXSIZE_CBUF (30 * 255) + +/* "expanded head": item head expanded by a content position and a by boundary information + * potentially inserted "to the left" of the item */ +typedef struct { + picodata_itemhead_t head; + picoos_uint16 cind; + picoos_uint8 boundstrength; /* bstrength to the left, 0 if not set */ + picoos_uint8 phrasetype; /* btype for following phrase, 0 if not set */ + picoos_int16 sildur; /* silence duration for boundary, -1 if not set */ +} picospho_headx_t; + + + +#define SPHO_MSGSTR_SIZE 32 + +/** object : SentPhoUnit + * shortcut : spho + * derived from : picodata_ProcessingUnit + */ +typedef struct spho_subobj { + picoos_Common common; + + /* we use int16 for buffer positions so we can indicate exceptional positions (invalid etc.) with negative + * integers */ + picoos_uint8 procState; /* for next processing step decision */ + + /* buffer for item headers */ + picoos_uint8 tmpbuf[PICODATA_MAX_ITEMSIZE]; /* tmp. location for an item */ + + picospho_headx_t headx[SPHO_MAXNR_HEADX]; /* "expanded head" buffer */ + picoos_uint16 headxBufSize; /* actually allocated size (if one day headxBuf is allocated dynamically) */ + picoos_uint16 headxReadPos, headxWritePos; + + picoos_uint8 cbuf[SPHO_MAXSIZE_CBUF]; + picoos_uint16 cbufBufSize; /* actually allocated size */ + picoos_uint16 cbufWritePos; /* next position to write to, 0 if buffer empty */ + + picoos_uint8 outBuf[PICODATA_BUFSIZE_DEFAULT]; /* internal output buffer to hold just one item */ + picoos_uint16 outBufSize; /* actually allocated size (if one day outBuf is allocated dynamically) */ + picoos_uint16 outReadPos; /* next pos to read from inBuf for output */ + + /* picoos_int16 outWritePos; */ /* next pos to output from in buf */ + + picoos_uint8 sylBuf[255]; /* internal buffer to hold contents of syl item to be output */ + picoos_uint8 sylReadPos, sylWritePos; /* next pos to read from sylBuf, next pos to write to sylBuf */ + + /* buffer for internal calculation of transducer */ + picotrns_AltDesc altDescBuf; + /* the number of AltDesc in the buffer */ + picoos_uint16 maxAltDescLen; + + /* the input to a transducer should not be larger than PICOTRNS_MAX_NUM_POSSYM + * so the output may expand (up to 4*PICOTRNS_MAX_NUM_POSSYM) */ + + picotrns_possym_t phonBufA[4 * PICOTRNS_MAX_NUM_POSSYM + 1]; + picotrns_possym_t phonBufB[4 * PICOTRNS_MAX_NUM_POSSYM + 1]; + picotrns_possym_t * phonBuf; + picotrns_possym_t * phonBufOut; + picoos_uint16 phonReadPos, phonWritePos; /* next pos to read from phonBufIn, next pos to write to phonBufIn */ + + picoos_int16 activeStartPos; /* start position of items to be treated (at end of left context) */ + picoos_int16 penultima, activeEndPos; /* positions of last two bounds/words; SPHO_POS_INVALID means uninitialized */ + picoos_int16 lastPhraseBoundPos; /* position of the last bound encountered (<0 if inexistent or not reachable */ + picoos_uint8 lastPhraseType; /* phrase type of the last phrase boundary, 0 if not set */ + + picoos_uint8 needMoreInput, /* more data necessary to decide on token */ + suppressParseWordBound, /* dont produce word boundary */ + suppressRecombWordBound, /* dont produce word boundary */ + breakPending, /* received a break but didn't interpret it yet */ + /* sentEnd, */ /* sentence end detected */ + force, /* in forced state */ + wordStarted, /* is it the first syl in the word: expect POS */ + sentenceStarted; + + picoos_uint16 breakTime; /* time argument of the pending break command */ + + picoos_uint8 feedFollowState; /* where to return after feed */ + + /* fst knowledge bases */ + picoos_uint8 numFsts; + picokfst_FST fst[PICOKNOW_MAX_NUM_SPHO_FSTS]; + picoos_uint8 curFst; /* the fst to be applied next */ + + /* fixed ids knowledge base */ + picoktab_FixedIds fixedIds; + + /* phones kb */ + picoktab_Phones phones; + + /* some soecial ids from phones */ + picoos_uint8 primStressId, secondStressId, syllSepId; + +} spho_subobj_t; + + +static pico_status_t sphoReset(register picodata_ProcessingUnit this) +{ + + spho_subobj_t * spho; + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(this->common->em, + PICO_ERR_NULLPTR_ACCESS, NULL, NULL); + } + spho = (spho_subobj_t *) this->subObj; + + spho->curFst = 0; + +/* processing state */ + spho->procState = SPHO_STEPSTATE_INIT; + spho->needMoreInput = TRUE; + spho->suppressParseWordBound = FALSE; + spho->suppressRecombWordBound = FALSE; + spho->breakPending = FALSE; + spho->force = 0; + spho->sentenceStarted = 0; + + + /* item buffer headx/cbuf */ + spho->headxBufSize = SPHO_MAXNR_HEADX; + spho->headxReadPos = 0; + spho->headxWritePos = 0; + + spho->cbufWritePos = 0; + spho->cbufBufSize = SPHO_MAXSIZE_CBUF; + + /* possym buffer */ + spho->phonBuf = spho->phonBufA; + spho->phonBufOut = spho->phonBufB; + spho->phonReadPos = 0; + + /* overlapping */ + spho->activeStartPos = 0; + spho->penultima = SPHO_POS_INVALID; + spho->activeEndPos = SPHO_POS_INVALID; + + return PICO_OK; +} + + +static pico_status_t sphoInitialize(register picodata_ProcessingUnit this, picoos_int32 resetMode) +{ + picoos_uint8 i; + spho_subobj_t * spho; + picokfst_FST fst; + + picoknow_kb_id_t myKbIds[PICOKNOW_MAX_NUM_SPHO_FSTS] = PICOKNOW_KBID_SPHO_ARRAY; + + PICODBG_DEBUG(("init")); + + if (NULL == this || NULL == this->subObj) { + return picoos_emRaiseException(this->common->em, + PICO_ERR_NULLPTR_ACCESS, NULL, NULL); + } + + spho = (spho_subobj_t *) this->subObj; + + spho->numFsts = 0; + + spho->curFst = 0; + + for (i = 0; ivoice->kbArray[myKbIds[i]]); + if (NULL != fst) { + spho->fst[spho->numFsts++] = fst; + } + } + spho->fixedIds = picoktab_getFixedIds(this->voice->kbArray[PICOKNOW_KBID_FIXED_IDS]); + spho->phones = picoktab_getPhones(this->voice->kbArray[PICOKNOW_KBID_TAB_PHONES]); + + spho->syllSepId = picoktab_getSyllboundID(spho->phones); + spho->primStressId = picoktab_getPrimstressID(spho->phones); + spho->secondStressId = picoktab_getSecstressID(spho->phones); + + PICODBG_DEBUG(("got %i fsts", spho->numFsts)); + + + return sphoReset(this); + +} + +static picodata_step_result_t sphoStep(register picodata_ProcessingUnit this, + picoos_int16 mode, picoos_uint16 *numBytesOutput); + + + + +static pico_status_t sphoTerminate(register picodata_ProcessingUnit this) +{ + return PICO_OK; +} + + +static pico_status_t sphoSubObjDeallocate(register picodata_ProcessingUnit this, + picoos_MemoryManager mm) +{ + spho_subobj_t * spho; + + spho = (spho_subobj_t *) this->subObj; + + if (NULL != this) { + if (NULL != this->subObj) { + spho = (spho_subobj_t *) (this->subObj); + picotrns_deallocate_alt_desc_buf(spho->common->mm,&spho->altDescBuf); + picoos_deallocate(mm, (void *) &this->subObj); + } + } + return PICO_OK; +} + +picodata_ProcessingUnit picospho_newSentPhoUnit(picoos_MemoryManager mm, + picoos_Common common, picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, picorsrc_Voice voice) +{ + spho_subobj_t * spho; + + picodata_ProcessingUnit this = picodata_newProcessingUnit(mm, common, cbIn, cbOut, voice); + if (this == NULL) { + return NULL; + } + + this->initialize = sphoInitialize; + this->step = sphoStep; + this->terminate = sphoTerminate; + this->subDeallocate = sphoSubObjDeallocate; + + this->subObj = picoos_allocate(mm, sizeof(spho_subobj_t)); + if (this->subObj == NULL) { + picoos_deallocate(mm, (void **)(void*)&this); + return NULL; + } + spho = (spho_subobj_t *) this->subObj; + + spho->common = this->common; + + /* these are given by the pre-allocated array sizes */ + spho->outBufSize = PICODATA_BUFSIZE_DEFAULT; + + + spho->altDescBuf = picotrns_allocate_alt_desc_buf(spho->common->mm, SPHO_MAX_ALTDESC_SIZE, &spho->maxAltDescLen); + if (NULL == spho->altDescBuf) { + picotrns_deallocate_alt_desc_buf(spho->common->mm,&spho->altDescBuf); + picoos_emRaiseException(spho->common->em,PICO_EXC_OUT_OF_MEM, NULL,NULL); + return NULL; + } + + sphoInitialize(this, PICO_RESET_FULL); + return this; +} + + +/* ***********************************************************************/ +/* process buffered item list */ +/* ***********************************************************************/ + + +/* shift relevant data in headx/'cbuf' (between 'readPos' incl and writePos non-incl) to 'start'. + * modify read/writePos accordingly */ +static picoos_int16 shift_range_left_1(spho_subobj_t *spho, picoos_int16 * from, picoos_int16 to) +{ + + /* remember shift parameters for cbuf */ + picoos_uint16 + c_i, + c_j, + c_diff, + c_writePos, + i, + j, + diff, + writePos; + i = to; + j = *from; + diff = j-i; + writePos = spho->headxWritePos; + c_i = spho->headx[to].cind; + if (j < writePos) { + c_j = spho->headx[j].cind; + } else { + c_j = spho->cbufWritePos; + } + c_diff = c_j - c_i; + c_writePos = spho->cbufWritePos; + + PICODBG_DEBUG(( + "shifting buffer region [%i,%i[ down to %i",*from, writePos, to + )); + + + /* PICODBG_ASSERT((i j) { + return -1; + } + /* shift cbuf */ + while (c_j < c_writePos) { + spho->cbuf[c_i++] = spho->cbuf[c_j++]; + } + /* shift headx */ + while (j < writePos) { + spho->headx[j].cind -= c_diff; + spho->headx[i++] = spho->headx[j++]; + } + spho->headxWritePos -= diff; + *from = to; + spho->cbufWritePos -= c_diff; + /* */ + PICODBG_DEBUG(( + "readPos,WritePos are now [%i,%i[, returning shift amount %i",*from, spho->headxWritePos, diff + )); + return diff; +} + +static pico_status_t sphoAddPhoneme(register spho_subobj_t *spho, picoos_int16 pos, picoos_int16 sym) { + picoos_uint8 plane, unshifted; + /* just for debuging */ + unshifted = picotrns_unplane(sym,&plane); + PICODBG_TRACE(("adding %i/%i (%c on plane %i) at phonBuf[%i]",pos,sym,unshifted,plane,spho->phonWritePos)); + if (2* PICOTRNS_MAX_NUM_POSSYM <= spho->phonWritePos) { + /* not an error! */ + PICODBG_DEBUG(("couldn't add because phon buffer full")); + return PICO_EXC_BUF_OVERFLOW; + } else { + spho->phonBuf[spho->phonWritePos].pos = pos; + spho->phonBuf[spho->phonWritePos].sym = sym; + spho->phonWritePos++; + return PICO_OK; + } +} + +static pico_status_t sphoAddStartPhoneme(register spho_subobj_t *spho) { + return sphoAddPhoneme(spho, PICOTRNS_POS_IGNORE, + (PICOKFST_PLANE_INTERN << 8) + spho->fixedIds->phonStartId); +} + +static pico_status_t sphoAddTermPhonemes(register spho_subobj_t *spho, picoos_uint16 pos) { + return sphoAddPhoneme(spho, pos, + (PICOKFST_PLANE_PB_STRENGTHS << 8) + PICODATA_ITEMINFO1_BOUND_SEND) + && sphoAddPhoneme(spho, PICOTRNS_POS_IGNORE, + (PICOKFST_PLANE_INTERN << 8) + spho->fixedIds->phonTermId); +} + +/* return "syllable accent" (or prominence) symbol, given "word accent" symbol 'wacc' and stress value (no=0, primary=1, secondary=2) */ +static picoos_uint16 sphoGetSylAccent(register spho_subobj_t *spho, + picoos_uint8 wacc, picoos_uint8 sylStress) +{ + PICODBG_ASSERT(sylStress <= 2); + + spho = spho; /* avoid warning "var not used in this function"*/ + + switch (sylStress) { + case 0: /* non-stressed syllable gets no prominence */ + /* return spho->fixedIds->accId[0]; */ + return PICODATA_ACC0; + break; + case 1: /* primary-stressed syllable gets word prominence */ + return wacc; + break; + case 2: /* secondary-stressed syllable gets no prominence or secondary stress prom. (4) */ + return (PICODATA_ACC0 == wacc) ? PICODATA_ACC0 + : PICODATA_ACC4; + /*return (spho->fixedIds->accId[0] == wacc) ? spho->fixedIds->accId[0] + : spho->fixedIds->accId[4]; */ + break; + default: + /* never occurs :-) */ + return PICODATA_ACC0; + break; + } +} + + +/* ***********************************************************************/ +/* extract phonemes of an item into a phonBuf */ +/* ***********************************************************************/ +static pico_status_t sphoExtractPhonemes(register picodata_ProcessingUnit this, + register spho_subobj_t *spho, picoos_uint16 pos, + picoos_uint8 convertAccents, picoos_uint8 * suppressWB) +{ + pico_status_t rv = PICO_OK; + picoos_uint16 i, j; + picoos_int16 fstSymbol; + picoos_uint8 curStress; + picotrns_possym_t tmpPosSym; + picoos_uint16 oldPos, curPos; + picodata_itemhead_t * head; + picoos_uint8* content; + +#if defined(PICO_DEBUG) + picoos_char msgstr[SPHO_MSGSTR_SIZE]; +#endif + + + /* + Items considered in a transduction are a BOUND or a WORDPHON item. its starting offset within the + headxBuf is given as 'pos'. + Elements that go into the transduction receive "their" position in the buffer. + */ + + oldPos = spho->phonWritePos; + + head = &(spho->headx[pos].head); + content = spho->cbuf + spho->headx[pos].cind; + + PICODBG_TRACE(("doing item %s\n", + picodata_head_to_string(head,msgstr,SPHO_MSGSTR_SIZE))); + + switch (head->type) { + case PICODATA_ITEM_BOUND: + /* map SBEG, SEND and TERM (as sentence closing) to SEND */ + fstSymbol = (PICODATA_ITEMINFO1_BOUND_SBEG == head->info1 || PICODATA_ITEMINFO1_BOUND_TERM == head->info1) ? PICODATA_ITEMINFO1_BOUND_SEND : head->info1; + PICODBG_TRACE(("found bound of type %c\n",head->info1)); + /* BOUND() */ + /* insert bound strength */ + PICODBG_TRACE(("inserting phrase bound phoneme %c and setting suppresWB=1\n",fstSymbol)); + fstSymbol += (PICOKFST_PLANE_PB_STRENGTHS << 8); + rv = sphoAddPhoneme(spho,pos,fstSymbol); + /* phrase type not used */ + /* suppress next word boundary */ + (*suppressWB) = 1; + break; + + case PICODATA_ITEM_WORDPHON: + /* WORDPHON(POS,WACC)phon */ + PICODBG_TRACE(("found WORDPHON")); + /* insert word boundary if not suppressed */ + if (!(*suppressWB)) { + fstSymbol = (PICOKFST_PLANE_PB_STRENGTHS << 8) + PICODATA_ITEMINFO1_BOUND_PHR0; + PICODBG_TRACE(("adding word boundary phone")); + rv = sphoAddPhoneme(spho,pos,fstSymbol); + } + (*suppressWB) = 0; + /* for the time being, we force to use POS so we can transduce all fsts in a row without reconsulting the items */ + + + /* If 'convertAccents' then the accentuation is not directly encoded. It rather influences the mapping of + * the word accent symbol to the actual accent phoneme which is put after the syllable separator. */ + if (convertAccents) { + PICODBG_TRACE(("converting accents")); + /* extracting phonemes IN REVERSE order replacing syllable symbols with prominence symbols */ + curPos = spho->phonWritePos; + curStress = 0; /* no stress */ + for (i = head->len; i > 0 ;) { + i--; + if (spho->primStressId == content[i]) { + curStress = 1; + PICODBG_DEBUG(("skipping primary stress at pos %i (in 1 .. %i)",i, head->len)); + continue; /* skip primary stress symbol */ + } else if (spho->secondStressId == content[i]) { + curStress = 2; + PICODBG_DEBUG(("skipping secondary stress at pos %i (in 1 .. %i)",i, head->len)); + continue; /* skip secundary stress symbol */ + } else if (spho->syllSepId == content[i]) { + fstSymbol = (PICOKFST_PLANE_POS << 8) + head->info1; + rv = sphoAddPhoneme(spho, pos, fstSymbol); + /* replace syllSepId by combination of syllable stress and word prominence */ + fstSymbol = sphoGetSylAccent(spho,head->info2,curStress); + curStress = 0; + /* add accent */ + fstSymbol += (PICOKFST_PLANE_ACCENTS << 8); + rv = sphoAddPhoneme(spho,pos,fstSymbol); + if (PICO_OK != rv) { + break; + } + /* and keep syllable boundary */ + fstSymbol = (PICOKFST_PLANE_PHONEMES << 8) + content[i]; + } else { + /* normal phoneme */ + fstSymbol = (PICOKFST_PLANE_PHONEMES << 8) + content[i]; + } + if (PICO_OK == rv) { + rv = sphoAddPhoneme(spho,pos,fstSymbol); + } + } + if (PICO_OK == rv) { + /* bug 366: we position the "head" into the item header and not on the first phoneme + * because there might be no phonemes at all */ + /* insert head of the first syllable of a word */ + fstSymbol = (PICOKFST_PLANE_POS << 8) + head->info1; + rv = sphoAddPhoneme(spho,pos,fstSymbol); + fstSymbol = sphoGetSylAccent(spho,head->info2,curStress); + curStress = 0; + fstSymbol += (PICOKFST_PLANE_ACCENTS << 8); + rv = sphoAddPhoneme(spho,pos,fstSymbol); + } + if (PICO_OK == rv) { + /* invert sympos portion */ + i = curPos; + j=spho->phonWritePos-1; + while (i < j) { + tmpPosSym.pos = spho->phonBuf[i].pos; + tmpPosSym.sym = spho->phonBuf[i].sym; + spho->phonBuf[i].pos = spho->phonBuf[j].pos; + spho->phonBuf[i].sym = spho->phonBuf[j].sym; + spho->phonBuf[j].pos = tmpPosSym.pos; + spho->phonBuf[j].sym = tmpPosSym.sym; + i++; + j--; + } + } + } else { /* convertAccents */ + for (i = 0; i len; i++) { + fstSymbol = (PICOKFST_PLANE_PHONEMES << 8) + content[i]; + rv = sphoAddPhoneme(spho,pos,fstSymbol); + } + } + break; + default: + picoos_emRaiseException(this->common->em,rv,NULL,NULL); + break; + } /* switch(head->type) */ + if (PICO_OK != rv) { + spho->phonWritePos = oldPos; + } + return rv; +} + + + + + +#define SPHO_POSSYM_OK 0 +#define SPHO_POSSYM_OUT_OF_RANGE 1 +#define SPHO_POSSYM_END 2 +#define SPHO_POSSYM_INVALID -3 +/* *readPos is the next position in phonBuf to be read, and *writePos is the first position not to be read (may be outside + * buf). + * 'rangeEnd' is the first possym position outside the desired range. + * Possible return values: + * SPHO_POSSYM_OK : 'pos' and 'sym' are set to the read possym, *readPos is advanced + * SPHO_POSSYM_OUT_OF_RANGE : pos is out of range. 'pos' is set to that of the read possym, 'sym' is undefined + * SPHO_POSSYM_UNDERFLOW : no more data in buf. 'pos' is set to PICOTRNS_POS_INVALID, 'sym' is undefined + * SPHO_POSSYM_INVALID : "strange" pos. 'pos' is set to PICOTRNS_POS_INVALID, 'sym' is undefined + */ +static pico_status_t getNextPosSym(spho_subobj_t * spho, picoos_int16 * pos, picoos_int16 * sym, + picoos_int16 rangeEnd) { + /* skip POS_IGNORE */ + while ((spho->phonReadPos < spho->phonWritePos) && (PICOTRNS_POS_IGNORE == spho->phonBuf[spho->phonReadPos].pos)) { + PICODBG_DEBUG(("ignoring phone at spho->phonBuf[%i] because it has pos==IGNORE",spho->phonReadPos)); + spho->phonReadPos++; + } + if ((spho->phonReadPos < spho->phonWritePos)) { + *pos = spho->phonBuf[spho->phonReadPos].pos; + if ((PICOTRNS_POS_INSERT == *pos) || ((0 <= *pos) && (*pos < rangeEnd))) { + *sym = spho->phonBuf[spho->phonReadPos++].sym; + return SPHO_POSSYM_OK; + } else if (*pos < 0){ /* *pos is "strange" (e.g. POS_INVALID) */ + return SPHO_POSSYM_INVALID; + } else { + return SPHO_POSSYM_OUT_OF_RANGE; + } + } else { + /* no more possyms to read */ + *pos = PICOTRNS_POS_INVALID; + return SPHO_POSSYM_END; + } +} + + + +/** Calculate bound strength modified by transduction + * + * Given the original bound strength 'orig' and the desired target strength 'target' (suggested by fst), + * calculate the modified bound strength. + * + * @param orig original bound strength + * @param target target bound strength + * @return resulting bound strength + */ +static picoos_uint8 fstModifiedBoundStrength(picoos_uint8 orig, picoos_uint8 target) +{ + switch (orig) { + case PICODATA_ITEMINFO1_BOUND_PHR1: + case PICODATA_ITEMINFO1_BOUND_PHR2: + /* don't allow primary phrase bounds to be demoted to word bound */ + if (PICODATA_ITEMINFO1_BOUND_PHR0 == target) { + return PICODATA_ITEMINFO1_BOUND_PHR3; + } + case PICODATA_ITEMINFO1_BOUND_PHR0: + case PICODATA_ITEMINFO1_BOUND_PHR3: + return target; + break; + default: + /* don't allow bounds other than phrase or word bounds to be changed */ + return orig; + break; + } +} + +/** Calculate bound strength modified by a \ command + * + * Given the original (predicted and possibly fst-modified) bound strength, and a time value from an + * overwriding \ command, calculate the modified bound strength. + * + * @param orig original bound strength + * @param time time given as property of \ command + * @param wasPrimary + * @return modified bound strength + */ +static picoos_uint8 breakModifiedBoundStrength(picoos_uint8 orig, picoos_uint16 time, picoos_bool wasPrimary) +{ + picoos_uint8 modified = (0 == time) ? PICODATA_ITEMINFO1_BOUND_PHR3 : + (50 < time) ? PICODATA_ITEMINFO1_BOUND_PHR1 : PICODATA_ITEMINFO1_BOUND_PHR2; + switch (orig) { + /* for word and phrase breaks, return 'modified', unless a non-silence gets time==0, in which + * case return no break (word break) */ + case PICODATA_ITEMINFO1_BOUND_PHR0: + if (0 == time) { + return PICODATA_ITEMINFO1_BOUND_PHR0; + } + case PICODATA_ITEMINFO1_BOUND_PHR3: + if (!wasPrimary && (0 == time)) { + return PICODATA_ITEMINFO1_BOUND_PHR0; + } + case PICODATA_ITEMINFO1_BOUND_PHR1: + case PICODATA_ITEMINFO1_BOUND_PHR2: + return modified; + break; + default: + return orig; + break; + } +} + +static picoos_bool breakStateInterrupting(picodata_itemhead_t * head, + picoos_bool * breakBefore, picoos_bool * breakAfter) { + + picoos_bool result = 1; + + *breakBefore = 0; + *breakAfter = 0; + + if (PICODATA_ITEM_WORDPHON == head->type) { + + } else if (PICODATA_ITEM_CMD == head->type) { + if ((PICODATA_ITEMINFO1_CMD_PLAY == head->info1) + || (PICODATA_ITEMINFO1_CMD_SAVE == head->info1) + || (PICODATA_ITEMINFO1_CMD_UNSAVE == head->info1)) { + *breakBefore = 1; + *breakAfter = 1; + } else if (PICODATA_ITEMINFO1_CMD_SAVE == head->info1) { + *breakBefore = 1; + } else if (PICODATA_ITEMINFO1_CMD_UNSAVE == head->info1) { + *breakAfter = 1; + } else if (PICODATA_ITEMINFO1_CMD_IGNSIG == head->info1) { + if (PICODATA_ITEMINFO2_CMD_START == head->info2) { + *breakBefore = 1; + } else { + *breakAfter = 1; + } + } + } else { + result = 0; + } + return result; +} + + +static void putSideBoundToOutput(spho_subobj_t * spho) +{ + + picodata_itemhead_t ohead; + picoos_uint8 ocontent[2*sizeof(picoos_uint16)]; + picoos_int16 sildur; + picoos_uint16 clen; + + /* create boundary */ + ohead.type = PICODATA_ITEM_BOUND; + ohead.info1 = spho->headx[spho->outReadPos].boundstrength; + ohead.info2 = spho->headx[spho->outReadPos].phrasetype; + sildur = spho->headx[spho->outReadPos].sildur; + if ((sildur < 0) + || (PICODATA_ITEMINFO1_BOUND_PHR0 == ohead.info1) + || (PICODATA_ITEMINFO1_BOUND_PHR3 == ohead.info1)) { + PICODBG_DEBUG(("outputting a bound of strength '%c' and type '%c' without duration constraints",ohead.info1, ohead.info2)); + ohead.len = 0; + } else { + picoos_uint32 pos = 0; + picoos_write_mem_pi_uint16(ocontent,&pos,sildur); + picoos_write_mem_pi_uint16(ocontent,&pos,sildur); + PICODBG_DEBUG(("outputting a bound of strength '%c' and type '%c' with duration constraints [%i,%i]",ohead.info1, ohead.info2,sildur, sildur)); + ohead.len = pos; + } + picodata_put_itemparts(&ohead, ocontent, ohead.len, + spho->outBuf, spho->outBufSize, &clen); + /* disable side bound */ + spho->headx[spho->outReadPos].boundstrength = 0; +} + +/** Set bound strength and sil dur. + * + * given the original bound strength 'orig_strength' and the fst-suggested bound strength 'fst_strength' + * and possibly being in a pending break state, calculate the resulting bound strength and set boundstrength + * and sildur of the current item (spho->headx[spho->outReadPos]) accordingly. + * if a boundstrength was set, also calculate the phrasetype and if necessary (and reachable), modify the phrase type + * of the previous phrase boundary. + * + * @param spho + * @param orig_strength + * @param orig_type + * @param fst_strength + */ +static void setSideBound(spho_subobj_t * spho, picoos_uint8 orig_strength, picoos_uint8 orig_type, picoos_uint8 fst_strength) { + picoos_uint8 strength; + + /* insert modified bound according to transduction symbol, if any */ + if (PICODATA_ITEMINFO1_NA == orig_strength) { + /* no original/fst strength given */ + orig_strength = PICODATA_ITEMINFO1_BOUND_PHR0; + strength = PICODATA_ITEMINFO1_BOUND_PHR0; + } else { + strength = fstModifiedBoundStrength(orig_strength,fst_strength); + spho->headx[spho->outReadPos].boundstrength = strength; + spho->headx[spho->outReadPos].sildur = -1; + PICODBG_DEBUG(("setting bound strength to fst-suggested value %c (was %c)",strength, spho->headx[spho->outReadPos].boundstrength, spho->breakTime)); + } + + /* insert modified bound according to pending break, if any */ + if (spho->breakPending) { + /* the calculation is based on the fst-modified value (because this is what the customer wants to + * override) + */ + strength = breakModifiedBoundStrength(strength, spho->breakTime, (PICODATA_ITEMINFO1_BOUND_PHR1 == orig_strength)); + PICODBG_DEBUG(("setting bound strength to break-imposed value %c (was %c) and time to %i",strength, spho->headx[spho->outReadPos].boundstrength, spho->breakTime)); + spho->headx[spho->outReadPos].boundstrength = strength; + spho->headx[spho->outReadPos].sildur = spho->breakTime; + spho->breakPending = FALSE; + } + if (spho->headx[spho->outReadPos].boundstrength) { + /* we did set a bound strength, possibly promoting or demoting a boundary; now set the phrase type + * possibly also changing the phrase type of the previous phrase bound + */ + picoos_uint8 fromPhrase = ((PICODATA_ITEMINFO1_BOUND_PHR0 != orig_strength)); + picoos_uint8 toPhrase = ((PICODATA_ITEMINFO1_BOUND_PHR0 != strength)); + + PICODBG_DEBUG(("setting phrase type (wasPhrase=%i, isPhrase=%i)",fromPhrase,toPhrase)); + if (toPhrase) { + if (fromPhrase) { + spho->lastPhraseType = orig_type; + } else { /*promote */ + if (spho->activeStartPos <= spho->lastPhraseBoundPos) { + /* we still can change prev phrase bound */ + /* since a new phrase boundary is introduced, we have to 'invent' + * an additional phrase type here. For that, we have to use some of the + * knowledge that otherwise is handled in picoacph. + */ + spho->headx[spho->lastPhraseBoundPos].phrasetype + = PICODATA_ITEMINFO2_BOUNDTYPE_P; + } + } + spho->lastPhraseBoundPos = spho->outReadPos; + spho->headx[spho->lastPhraseBoundPos].phrasetype + = spho->lastPhraseType; + + } else { + spho->headx[spho->outReadPos].phrasetype = PICODATA_ITEMINFO2_NA; + if (fromPhrase) { /* demote */ + spho->lastPhraseType = orig_type; + if (spho->activeStartPos <= spho->lastPhraseBoundPos) { + /* we still can change prev phrase bound */ + spho->headx[spho->lastPhraseBoundPos].phrasetype + = spho->lastPhraseType; + } + } + } + } +} + + +/* ***********************************************************************/ +/* sphoStep function */ +/* ***********************************************************************/ + + +static picodata_step_result_t sphoStep(register picodata_ProcessingUnit this, + picoos_int16 mode, picoos_uint16 * numBytesOutput) +{ + + register spho_subobj_t *spho; + pico_status_t rv= PICO_OK; + picoos_uint16 blen; + picodata_itemhead_t ihead, ohead; + picoos_uint8 *icontent; + picoos_uint16 nextInPos; +#if defined(PICO_DEBUG) + picoos_char msgstr[SPHO_MSGSTR_SIZE]; +#endif + + /* used in FEED and FEED_SYM */ + picoos_uint16 clen; + picoos_int16 pos, sym, sylsym; + picoos_uint8 plane; + + /* used in BOUNDS */ + picoos_bool breakBefore, breakAfter; + + /* pico_status_t rvP= PICO_OK; */ + + picoos_uint16 curPos /*, nextPos */; + picoos_uint16 remHeadxSize, remCbufSize; + + + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + spho = (spho_subobj_t *) this->subObj; + + mode = mode; /* avoid warning "var not used in this function"*/ + + *numBytesOutput = 0; + while (1) { /* exit via return */ + PICODBG_INFO(("doing state %i, headxReadPos: %d, headxWritePos: %d", + spho->procState, spho->headxReadPos, spho->headxWritePos)); + + switch (spho->procState) { + + case SPHO_STEPSTATE_INIT: + /* **********************************************************************/ + /* INIT */ + /* **********************************************************************/ + PICODBG_DEBUG(("INIT")); + /* (re)set values for PARSE */ + spho->penultima = SPHO_POS_INVALID; + spho->activeEndPos = SPHO_POS_INVALID; + spho->headxReadPos = 0; + spho->phonReadPos = 0; + spho->phonWritePos = 0; + spho->lastPhraseType = PICODATA_ITEMINFO2_NA; + spho->lastPhraseBoundPos = -1; + + spho->procState = SPHO_STEPSTATE_COLLECT; + break; + + + case SPHO_STEPSTATE_COLLECT: + /* **********************************************************************/ + /* COLLECT */ + /* **********************************************************************/ + /* collect state: get items from charBuf and store in + * internal inBuf + */ + PICODBG_TRACE(("COLLECT")); + rv = PICO_OK; + remHeadxSize = spho->headxBufSize - spho->headxWritePos; + remCbufSize = spho->cbufBufSize - spho->cbufWritePos; + curPos = spho->headxWritePos; + while ((PICO_OK == rv) && (remHeadxSize > 0) && (remCbufSize > 0)) { + PICODBG_DEBUG(("COLLECT getting item at headxWritePos %i (remaining %i)",spho->headxWritePos, remHeadxSize)); + rv = picodata_cbGetItem(this->cbIn, spho->tmpbuf, PICODATA_MAX_ITEMSIZE, &blen); + if (PICO_OK == rv) { + rv = picodata_get_itemparts(spho->tmpbuf, + PICODATA_MAX_ITEMSIZE, &(spho->headx[spho->headxWritePos].head), + &(spho->cbuf[spho->cbufWritePos]), remCbufSize, &blen); + if (PICO_OK == rv) { + spho->headx[spho->headxWritePos].cind = spho->cbufWritePos; + spho->headx[spho->headxWritePos].boundstrength = 0; + spho->headxWritePos++; + remHeadxSize--; + spho->cbufWritePos += blen; + remCbufSize -= blen; + } + } + } + if ((PICO_OK == rv) && ((remHeadxSize <= 0) || (remCbufSize <= 0))) { + rv = PICO_EXC_BUF_OVERFLOW; + } + + /* in normal circumstances, rv is either PICO_EOF (no more items in cbIn) or PICO_BUF_OVERFLOW + * (if no more items fit into headx) */ + if ((PICO_EOF != rv) && (PICO_EXC_BUF_OVERFLOW != rv)) { + PICODBG_DEBUG(("COLLECT ** problem getting item, unhandled, rv: %i", rv)); + picoos_emRaiseException(this->common->em, rv, + NULL, NULL); + return PICODATA_PU_ERROR; + } + if (PICO_EOF == rv) { /* there are no more items available */ + if (curPos < spho->headxWritePos) { /* we did get some new items */ + PICODBG_DEBUG(("COLLECT read %i items", + spho->headxWritePos - curPos)); + spho->needMoreInput = FALSE; + } + if (spho->needMoreInput) { /* not enough items to proceed */ + PICODBG_DEBUG(("COLLECT need more data, returning IDLE")); + return PICODATA_PU_IDLE; + } else { + spho->procState = SPHO_STEPSTATE_PROCESS_PARSE; + /* uncomment next to split into two steps */ + /* return PICODATA_PU_ATOMIC; */ + } + } else { /* input buffer full */ + PICODBG_DEBUG(("COLLECT input buffer full")); + if (spho->needMoreInput) { /* forced output because we can't get more data */ + spho->needMoreInput = FALSE; + spho->force = TRUE; + } + spho->procState = SPHO_STEPSTATE_PROCESS_PARSE; + } + break; + + case SPHO_STEPSTATE_PROCESS_PARSE: + + /* **********************************************************************/ + /* PARSE: items -> input pos/phon pairs */ + /* **********************************************************************/ + + /* parse one item at a time */ + /* If + * - the item is a sentence end or + * - it is the last item and force=1 or + * - the phon buffer is full + * then set inReadPos to 0 and go to TRANSDUCE + * else advance by one item */ + + /* look at the current item */ + PICODBG_TRACE(("PARSE")); + if (spho->headxReadPos >= spho->headxWritePos) { + /* no more items in headx */ + if (spho->force) { + PICODBG_INFO(("no more items in headx but we are forced to transduce")); + + /* headx is full; we are forced to transduce before reaching the sentence end */ + spho->force = FALSE; + if (SPHO_POS_INVALID == spho->activeEndPos) { + spho->activeEndPos = spho->headxReadPos; + } + spho->procState = SPHO_STEPSTATE_PROCESS_TRANSDUCE; + } else { + /* we try to get more data */ + PICODBG_INFO(("no more items in headx, try to collect more")); + spho->needMoreInput = TRUE; + spho->procState = SPHO_STEPSTATE_COLLECT; + } + break; + } + + ihead = spho->headx[spho->headxReadPos].head; + icontent = spho->cbuf + spho->headx[spho->headxReadPos].cind; + + PICODBG_DEBUG(("PARSE looking at item %s",picodata_head_to_string(&ihead,msgstr,SPHO_MSGSTR_SIZE))); + /* treat header */ + if (PICODATA_ITEM_BOUND == ihead.type) { + /* see if it is a sentence end or termination boundary (flush) */ + if ((PICODATA_ITEMINFO1_BOUND_SEND == ihead.info1) + || (PICODATA_ITEMINFO1_BOUND_TERM == ihead.info1)) { + PICODBG_INFO(("PARSE found sentence end or term BOUND")); + + if (spho->sentenceStarted) { + /* its the end of the sentence */ + PICODBG_INFO(("PARSE found sentence end")); + spho->sentenceStarted = 0; + /* there is no need for a right context; move the active end to the end */ + /* add sentence termination phonemes */ + sphoAddTermPhonemes(spho, spho->headxReadPos); + spho->headxReadPos++; + spho->activeEndPos = spho->headxReadPos; + /* we may discard all information up to activeEndPos, after processing of last + * sentence part + */ + spho->penultima = spho->activeEndPos; + + /* transduce */ + spho->procState = SPHO_STEPSTATE_PROCESS_TRANSDUCE; + /* uncomment to split */ + /* return PICODATA_PU_BUSY; */ + break; + } else { + if (PICODATA_ITEMINFO1_BOUND_TERM == ihead.info1) { + /* its the end of input (flush) */ + PICODBG_INFO(("PARSE forwarding input end (flush)")); + /* copy item unmodified */ + picodata_put_itemparts(&ihead, + icontent, + ihead.len, + spho->outBuf, spho->outBufSize, + &clen); + + spho->headxReadPos++; + spho->activeEndPos = spho->headxReadPos; + spho->penultima = SPHO_POS_INVALID; + spho->feedFollowState = SPHO_STEPSTATE_SHIFT; + spho->procState = SPHO_STEPSTATE_FEED; + break; + } else { + /* this should never happen */ + /* eliminate bound */ + spho->headxReadPos++; + spho->activeEndPos = spho->headxReadPos; + spho->penultima = SPHO_POS_INVALID; + PICODBG_ERROR(("PARSE found a sentence end without a sentence start; eliminated")); + } + } + } else if (PICODATA_ITEMINFO1_BOUND_SBEG == ihead.info1) { + /* its the start of the sentence */ + PICODBG_INFO(("PARSE found sentence start")); + /* add sentence starting phoneme */ + sphoAddStartPhoneme(spho); + + spho->sentenceStarted = 1; + } + } + + if ((PICODATA_ITEM_WORDPHON == ihead.type) + || (PICODATA_ITEM_BOUND == ihead.type)) { + /* if it is a word or a bound try to extract phonemes */ + PICODBG_INFO(("PARSE found WORD phon or phrase BOUND")); + rv = sphoExtractPhonemes(this, spho, spho->headxReadPos, + TRUE /* convertAccents */, + &spho->suppressParseWordBound); + if (PICO_OK == rv) { + PICODBG_INFO(("PARSE successfully returned from phoneme extraction")); + /* replace activeEndPos if the new item is a word, or activeEndPos was not set yet, or + * activeEndPos was a bound */ + if ((spho->activeStartPos <= spho->headxReadPos) && ((PICODATA_ITEM_WORDPHON == ihead.type) + || (SPHO_POS_INVALID == spho->activeEndPos) + || (PICODATA_ITEM_BOUND == spho->headx[spho->activeEndPos].head.type))) { + PICODBG_INFO(("PARSE found new activeEndPos: %i,%i -> %i,%i", + spho->penultima,spho->activeEndPos,spho->activeEndPos,spho->headxReadPos)); + spho->penultima = spho->activeEndPos; + spho->activeEndPos = spho->headxReadPos; + } + + } else if (PICO_EXC_BUF_OVERFLOW == rv) { + /* phoneme buffer cannot take this item anymore; + if the phoneme buffer has some contents, we are forced to transduce before reaching the sentence end + else we skip the (too long word) */ + PICODBG_INFO(("PARSE returned from phoneme extraction with overflow, number of phonemes in phonBuf: %i; forced to TRANSDUCE", spho->phonWritePos)); + if ((SPHO_POS_INVALID == spho->activeEndPos) || (spho->activeStartPos == spho->activeEndPos)) { + spho->activeEndPos = spho->headxReadPos; + } + spho->procState = SPHO_STEPSTATE_PROCESS_TRANSDUCE; + break; + } else { + PICODBG_ERROR(("PARSE returned from phoneme extraction with exception %i",rv)); + return (picodata_step_result_t)picoos_emRaiseException(this->common->em, + PICO_ERR_OTHER, NULL, NULL); + } + } else { + PICODBG_INFO(("PARSE found other item, passing over")); + /* it is "other" item, ignore */ + } + /* set pos at next item */ + PICODBG_INFO(("PARSE going to next item: %i -> %i",spho->headxReadPos, spho->headxReadPos + 1)); + spho->headxReadPos++; + break; + + case SPHO_STEPSTATE_PROCESS_TRANSDUCE: + + /* **********************************************************************/ + /* TRANSDUCE: transduction input pos/phon pairs to output pos/phon pairs */ + /* **********************************************************************/ + PICODBG_DEBUG(("TRANSDUCE (%i-th of %i fsts",spho->curFst+1, spho->numFsts)); + + /* termination condition first */ + if (spho->curFst >= spho->numFsts) { + +#if defined(PICO_DEBUG) + { + PICODBG_INFO_CTX(); + PICODBG_INFO_MSG(("result of all transductions: ")); + PICOTRNS_PRINTSYMSEQ(this->voice->kbArray[PICOKNOW_KBID_DBG], spho->phonBufOut, spho->phonWritePos); + PICODBG_INFO_MSG(("\n")); + } +#endif + + /* reset for next transduction */ + spho->curFst = 0; + /* prepare BOUNDS */ + spho->outReadPos = 0; + spho->phonReadPos = 0; + + spho->procState = SPHO_STEPSTATE_PROCESS_BOUNDS; + break; + } + + /* transduce from phonBufIn to PhonBufOut */ + { + + picoos_uint32 nrSteps; +#if defined(PICO_DEBUG) + { + PICODBG_INFO_CTX(); + PICODBG_INFO_MSG(("spho trying to transduce: ")); + PICOTRNS_PRINTSYMSEQ(this->voice->kbArray[PICOKNOW_KBID_DBG], spho->phonBuf, spho->phonWritePos); + PICODBG_INFO_MSG(("\n")); + } +#endif + rv = picotrns_transduce(spho->fst[spho->curFst], FALSE, + picotrns_printSolution, spho->phonBuf, spho->phonWritePos, spho->phonBufOut, + &spho->phonWritePos, + 4*PICOTRNS_MAX_NUM_POSSYM, spho->altDescBuf, + spho->maxAltDescLen, &nrSteps); + if (PICO_OK == rv) { +#if defined(PICO_DEBUG) + { + PICODBG_INFO_CTX(); + PICODBG_INFO_MSG(("result of transduction: (output symbols: %i)", spho->phonWritePos)); + PICOTRNS_PRINTSYMSEQ(this->voice->kbArray[PICOKNOW_KBID_DBG], spho->phonBufOut, spho->phonWritePos); + PICODBG_INFO_MSG(("\n")); + } +#endif + PICODBG_TRACE(("number of steps done in tranduction: %i", nrSteps)); + } else { + picoos_emRaiseWarning(this->common->em, PICO_WARN_FALLBACK,NULL,(picoos_char *)"phon buffer full"); + } + } + /* eliminate deep epsilons */ + picotrns_eliminate_epsilons(spho->phonBufOut, spho->phonWritePos, spho->phonBuf, + &spho->phonWritePos,4*PICOTRNS_MAX_NUM_POSSYM); + + spho->curFst++; + + /* return PICODATA_PU_ATOMIC */ + break; + + + case SPHO_STEPSTATE_PROCESS_BOUNDS: + /* ************************************************************************/ + /* BOUNDS: combine input item with pos/phon pairs to insert/modify bounds */ + /* ************************************************************************/ + + PICODBG_INFO(("BOUNDS")); + + /* get the suppressRecombWordBound in the left context */ + spho->suppressRecombWordBound = FALSE; + while (spho->outReadPos < spho->activeStartPos) { + /* look at the current item */ + ihead = spho->headx[spho->outReadPos].head; + /* icontent = spho->cbuf + spho->headx[spho->outReadPos].cind; */ + PICODBG_INFO(("in position %i, looking at item %s",spho->outReadPos,picodata_head_to_string(&ihead,msgstr,SPHO_MSGSTR_SIZE))); + if (PICODATA_ITEM_BOUND == ihead.type) { + spho->suppressRecombWordBound = TRUE; + } else if (PICODATA_ITEM_WORDPHON == ihead.type) { + spho->suppressRecombWordBound = FALSE; + } + spho->outReadPos++; + } + /* spho->outReadPos point now to the active region */ + + /* advance the phone reading pos to the active range */ + spho->phonReadPos = 0; + while (SPHO_POSSYM_OK == (rv = getNextPosSym(spho, &pos, &sym, + spho->activeStartPos))) { + /* ignore */ + } + PICODBG_INFO(("skipping left context phones results in %s", (SPHO_POSSYM_OUT_OF_RANGE==rv) ? "OUT_OF_RANGE" : (SPHO_POSSYM_END ==rv) ? "END" : "OTHER")); + + /* + * Align input items with transduced phones and note bound stregth changes and break commands + */ + + while (spho->outReadPos < spho->activeEndPos) { + + /* look at the current item */ + ihead = spho->headx[spho->outReadPos].head; + icontent = spho->cbuf + spho->headx[spho->outReadPos].cind; + nextInPos = spho->outReadPos + 1; + /* */ + PICODBG_INFO(("in position %i, looking at item %s",spho->outReadPos,picodata_head_to_string(&ihead,msgstr,SPHO_MSGSTR_SIZE))); + + if ((PICODATA_ITEM_BOUND == ihead.type) + || ((PICODATA_ITEM_WORDPHON == ihead.type) + && (!spho->suppressRecombWordBound))) { + /* there was a boundary originally */ + picoos_uint8 orig_strength, orig_type; + if (PICODATA_ITEM_BOUND == ihead.type) { + orig_strength = ihead.info1; + orig_type = ihead.info2; + spho->suppressRecombWordBound = TRUE; + } else { + orig_strength = PICODATA_ITEMINFO1_BOUND_PHR0; + orig_type = PICODATA_ITEMINFO2_NA; + } + /* i expect a boundary phone here */ + /* consume FST bound phones, consider pending break and set the side-bound */ + PICODBG_INFO(("got BOUND or WORDPHON item and expects corresponding phone")); + rv = getNextPosSym(spho, &pos, &sym, nextInPos); + if (SPHO_POSSYM_OK != rv) { + PICODBG_ERROR(("unexpected symbol or unexpected end of phoneme list (%s)", (SPHO_POSSYM_OUT_OF_RANGE==rv) ? "OUT_OF_RANGE" : (SPHO_POSSYM_END ==rv) ? "END" :"OTHER")); + return (picodata_step_result_t)picoos_emRaiseException(this->common->em, + PICO_ERR_OTHER, NULL, NULL); + } + sym = picotrns_unplane(sym, &plane); + /* */ + PICODBG_ASSERT((PICOKFST_PLANE_PB_STRENGTHS == plane)); + + /* insert modified bound according to transduction and possibly pending break */ + setSideBound(spho, orig_strength, orig_type, + (picoos_uint8) sym); + } else if ((PICODATA_ITEM_CMD == ihead.type) + && (PICODATA_ITEMINFO1_CMD_SIL == ihead.info1)) { + /* it's a SIL (break) command */ + picoos_uint16 time; + picoos_uint32 pos = 0; + picoos_read_mem_pi_uint16(icontent, &pos, &time); + if (spho->breakPending) { + spho->breakTime += time; + } else { + spho->breakTime = time; + spho->breakPending = TRUE; + } + } else if ((PICODATA_ITEM_CMD == ihead.type) && (PICODATA_ITEMINFO1_CMD_PLAY == ihead.info1)) { + /* insert break of at least one ms */ + if (!spho->breakPending || (spho->breakTime <= 0)) { + spho->breakTime = SPHO_SMALLEST_SIL_DUR; + spho->breakPending = TRUE; + } + setSideBound(spho, PICODATA_ITEMINFO1_NA, + PICODATA_ITEMINFO2_NA, PICODATA_ITEMINFO1_NA); + /* force following break to be at least one ms */ + spho->breakTime = SPHO_SMALLEST_SIL_DUR; + spho->breakPending = TRUE; + } else if (breakStateInterrupting(&ihead, &breakBefore, &breakAfter)) { + + if (breakBefore &&(!spho->breakPending || (spho->breakTime <= 0))) { + spho->breakTime = SPHO_SMALLEST_SIL_DUR; + spho->breakPending = TRUE; + } + setSideBound(spho, PICODATA_ITEMINFO1_NA, + PICODATA_ITEMINFO2_NA, PICODATA_ITEMINFO1_NA); + + if (breakAfter) { + spho->breakTime = SPHO_SMALLEST_SIL_DUR; + spho->breakPending = TRUE; + } + if (PICODATA_ITEM_WORDPHON == ihead.type) { + spho->suppressRecombWordBound = FALSE; + } + } + + /* skip phones of that item */ + while (SPHO_POSSYM_OK == (rv = getNextPosSym(spho, &pos, + &sym, nextInPos))) { + /* ignore */ + } + spho->outReadPos++; + } + + /* reset for RECOMB */ + spho->outReadPos = 0; + spho->phonReadPos = 0; + spho->suppressRecombWordBound = FALSE; + + spho->procState = SPHO_STEPSTATE_PROCESS_RECOMB; + return PICODATA_PU_ATOMIC; + + break; + + case SPHO_STEPSTATE_PROCESS_RECOMB: + /* **********************************************************************/ + /* RECOMB: combine input item with pos/phon pairs to output item */ + /* **********************************************************************/ + + PICODBG_TRACE(("RECOMB")); + + /* default place to come after feed: here */ + spho->feedFollowState = SPHO_STEPSTATE_PROCESS_RECOMB; + + /* check termination condition first */ + if (spho->outReadPos >= spho->activeEndPos) { + PICODBG_DEBUG(("RECOMB reached active region's end at %i",spho->outReadPos)); + spho->procState = SPHO_STEPSTATE_SHIFT; + break; + } + + /* look at the current item */ + ihead = spho->headx[spho->outReadPos].head; + icontent = spho->cbuf + spho->headx[spho->outReadPos].cind; + + PICODBG_DEBUG(("RECOMB looking at item %s",picodata_head_to_string(&ihead,msgstr,SPHO_MSGSTR_SIZE))); + + nextInPos = spho->outReadPos + 1; + + PICODBG_DEBUG(("RECOMB treating item in headx at pos %i",spho->outReadPos)); + if (nextInPos <= spho->activeStartPos) { /* we're in the (passive) left context. Just skip it */ + PICODBG_DEBUG(("RECOMB skipping item in the left context (%i <= %i)",nextInPos, spho->activeStartPos)); + if (PICODATA_ITEM_BOUND == ihead.type) { + spho->suppressRecombWordBound = 1; + } else if (PICODATA_ITEM_WORDPHON == ihead.type) { + spho->suppressRecombWordBound = 0; + } + + /* consume possyms */ + while (SPHO_POSSYM_OK == (rv = getNextPosSym(spho,&pos,&sym,nextInPos))) { + /* ignore */ + } + if (rv == SPHO_POSSYM_INVALID) { + return (picodata_step_result_t)picoos_emRaiseException(this->common->em, + PICO_ERR_OTHER, NULL, NULL); + } + spho->outReadPos = nextInPos; + } else { /* active region */ + if (spho->headx[spho->outReadPos].boundstrength) { +/* ***************** "side-bound" *********************/ + /* copy to outbuf */ + putSideBoundToOutput(spho); + /* mark as processed */ + spho->headx[spho->outReadPos].boundstrength = 0; + /* output it */ + spho->procState = SPHO_STEPSTATE_FEED; + } else if (PICODATA_ITEM_BOUND == ihead.type) { +/* ***************** BOUND *********************/ + /* expect a boundary phone here */ + PICODBG_DEBUG(("RECOMB got BOUND item and expects corresponding phone")); + rv = getNextPosSym(spho, &pos, &sym, nextInPos); + if (SPHO_POSSYM_OK != rv) { + PICODBG_ERROR(("unexpected symbol or unexpected end of phoneme list")); + return (picodata_step_result_t)picoos_emRaiseException( + this->common->em, PICO_ERR_OTHER, NULL, + NULL); + } + sym = picotrns_unplane(sym, &plane); + /* */ + PICODBG_ASSERT((PICOKFST_PLANE_PB_STRENGTHS == plane)); + + spho->suppressRecombWordBound = TRUE; /* if word following, don't need word boundary */ + /* just consume item and come back here*/ + spho->outReadPos = nextInPos; + + } else if (PICODATA_ITEM_WORDPHON == ihead.type) { +/* ***************** WORDPHON *********************/ + spho->wordStarted = TRUE; + /* i expect a word boundary symbol in this range unless a phrase boundary was encountered before */ + if (spho->suppressRecombWordBound) { + PICODBG_DEBUG(("RECOMB got WORDPHON item but skips expecting BOUND")); + spho->suppressRecombWordBound = FALSE; + } else { + PICODBG_DEBUG(("RECOMB got WORDPHON item and expects corresponding bound phone")); + rv = getNextPosSym(spho, &pos, &sym, nextInPos); + if (SPHO_POSSYM_OK != rv) { + PICODBG_ERROR(("unexpected symbol or unexpected end of phoneme list")); + return (picodata_step_result_t)picoos_emRaiseException(this->common->em, + PICO_ERR_OTHER, NULL, NULL); + } + } + spho->procState = SPHO_STEPSTATE_PROCESS_SYL; + } else if ((PICODATA_ITEM_CMD == ihead.type) && (PICODATA_ITEMINFO1_CMD_SIL == ihead.info1)) { +/* ***************** BREAK COMMAND *********************/ + /* just consume and come back here */ + PICODBG_DEBUG(("RECOMB consuming item from inBuf %i -> %i",spho->outReadPos, nextInPos)); + spho->outReadPos = nextInPos; + } else { +/* ***************** OTHER *********************/ + /* just copy item */ + PICODBG_DEBUG(("RECOMB found other item, just copying")); + picodata_put_itemparts(&ihead, icontent, ihead.len, + spho->outBuf, spho->outBufSize, &clen); + PICODBG_DEBUG(("RECOMB consuming item from inBuf %i -> %i",spho->outReadPos, nextInPos)); + spho->outReadPos = nextInPos; + /* and output it */ + spho->procState = SPHO_STEPSTATE_FEED; + } /* if (ihead.type) */ + + } + + /* return PICODATA_PU_BUSY; */ + break; + + case SPHO_STEPSTATE_PROCESS_SYL: + /* **********************************************************************/ + /* SYL: combine input word item with pos/phon pairs to syl output item */ + /* **********************************************************************/ + + /* consume all transduced phonemes with pos in in the range [spho->outReadPos,nextInPos[ */ + PICODBG_DEBUG(("SYL")); + + spho->feedFollowState = SPHO_STEPSTATE_PROCESS_SYL; + + /* look at the current item */ + ihead = spho->headx[spho->outReadPos].head; + icontent = spho->cbuf + spho->headx[spho->outReadPos].cind; + nextInPos = spho->outReadPos + 1; + PICODBG_DEBUG(("SYL (1) treating item in headx at pos %i",spho->outReadPos)); + /* create syllable item in ohead (head) and sylBuf (contents) */ + ohead.type = PICODATA_ITEM_SYLLPHON; + + PICODBG_TRACE(("SYL expects accent at phonBuf[%i] = (%i,%i) (outReadPos=%i)", spho->phonReadPos, spho->phonBuf[spho->phonReadPos].pos, spho->phonBuf[spho->phonReadPos].sym,spho->outReadPos)); + rv = getNextPosSym(spho,&pos,&sym,nextInPos); + if (SPHO_POSSYM_OK != rv) { + PICODBG_ERROR(("unexpected symbol or unexpected end of phoneme list (%i)",rv)); + return (picodata_step_result_t)picoos_emRaiseException(this->common->em, PICO_ERR_OTHER, NULL, NULL); + } + ohead.info2 = picotrns_unplane(sym, &plane); + PICODBG_ASSERT((PICOKFST_PLANE_ACCENTS == plane)); + PICODBG_DEBUG(("SYL sets accent to %c", sym)); + + /* for the time being, we force to use POS so we can transduce all fsts in a row without reconsulting the items */ + PICODBG_TRACE(("SYL expects POS")); + PICODBG_DEBUG(("SYL (2) treating item in inBuf range [%i,%i[",spho->outReadPos,nextInPos)); + rv = getNextPosSym(spho,&pos,&sym,nextInPos); + if (SPHO_POSSYM_OK != rv) { + PICODBG_ERROR(("unexpected symbol or unexpected end of phoneme list")); + return (picodata_step_result_t)picoos_emRaiseException(this->common->em, PICO_ERR_OTHER, NULL, NULL); + } + if (spho->wordStarted) { + spho->wordStarted = FALSE; + ohead.info1 = picotrns_unplane(sym, &plane); + /* */ + PICODBG_ASSERT(PICOKFST_PLANE_POS == plane); + /* */ + PICODBG_DEBUG(("SYL setting POS to %c", ohead.info1)); + } else { + ohead.info1 = PICODATA_ITEMINFO1_NA; + } + + PICODBG_DEBUG(("SYL (3) treating item in inBuf range [%i,%i[",spho->outReadPos,nextInPos)); + /* get phonemes of that syllable; stop if syllable boundary or outside word */ + sylsym = (PICOKFST_PLANE_PHONEMES << 8) + + spho->syllSepId; + PICODBG_DEBUG(("collecting syllable phonemes before headx position %i",nextInPos)); + spho->sylWritePos = 0; + while (SPHO_POSSYM_OK == (rv = getNextPosSym(spho,&pos,&sym,nextInPos)) && (sym != sylsym)) { + spho->sylBuf[spho->sylWritePos++] = picotrns_unplane(sym, &plane); + /* */ + PICODBG_TRACE(("SYL adding phoneme to syllable: (pos %i,sym %i)[plane %i,sym %c]",pos,sym,plane,sym & 0xFF)); + PICODBG_ASSERT((PICOKFST_PLANE_PHONEMES == plane)); + } + PICODBG_DEBUG(("SYL (4) treating item in inBuf range [%i,%i[",spho->outReadPos,nextInPos)); + ohead.len = spho->sylWritePos; + if (SPHO_POS_INVALID == rv) { + PICODBG_ERROR(("unexpected symbol or unexpected end of phoneme list")); + return (picodata_step_result_t)picoos_emRaiseException(this->common->em, PICO_WARN_INCOMPLETE, NULL, NULL); + } else if ((SPHO_POSSYM_OUT_OF_RANGE == rv) || (SPHO_POSSYM_END == rv)) { + PICODBG_DEBUG(("SYL arrived at end of word and/or end of phon buffer, go to next word")); + spho->outReadPos = nextInPos; /* advance to next item */ + spho->feedFollowState = SPHO_STEPSTATE_PROCESS_RECOMB; /* go to RECOMB after feed */ + } else { + PICODBG_ASSERT((sym == sylsym)); + } + PICODBG_DEBUG(("SYL (5) treating item in inBuf range [%i,%i[",spho->outReadPos,nextInPos)); + + if (ohead.len > 0) { + /* prepare syllable output */ + picodata_put_itemparts(&ohead, spho->sylBuf, + PICODATA_BUFSIZE_DEFAULT, spho->outBuf, + spho->outBufSize, &clen); + + spho->procState = SPHO_STEPSTATE_FEED; + } else { /* skip feeding output of empty syllable */ + spho->procState = spho->feedFollowState; + } + break; + + case SPHO_STEPSTATE_FEED: + /* **********************************************************************/ + /* FEED: output output item and proceed to feedFollowState */ + /* **********************************************************************/ + + PICODBG_DEBUG(("FEED")); + + PICODBG_DEBUG(("FEED putting outBuf item into cb")); + + /*feeding items to PU output buffer*/ + rv = picodata_cbPutItem(this->cbOut, spho->outBuf, + spho->outBufSize, &clen); + + PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG], + (picoos_uint8 *)"spho: ", + spho->outBuf, spho->outBufSize); + + if (PICO_EXC_BUF_OVERFLOW == rv) { + /* we have to redo this item */ + PICODBG_DEBUG(("FEED got overflow, returning ICODATA_PU_OUT_FULL")); + return PICODATA_PU_OUT_FULL; + } else if (PICO_OK == rv) { + *numBytesOutput += clen; + spho->procState = spho->feedFollowState; + PICODBG_DEBUG(("FEED ok, going back to procState %i", spho->procState)); + return PICODATA_PU_BUSY; + } else { + PICODBG_DEBUG(("FEED got exception %i when trying to output item",rv)); + spho->procState = spho->feedFollowState; + return (picodata_step_result_t)rv; + } + break; + + case SPHO_STEPSTATE_SHIFT: + /* **********************************************************************/ + /* SHIFT */ + /* **********************************************************************/ + /* If there exists a valid penultima, it should replace any left context (from 0 to activeStartPos) + * else discard the current active range (from activeStartPos to activeEndPos), leaving the current + * left context intact. Often, PARSE would move activeStartPos to 0, so that there is no left context + * after the shift. + */ + + PICODBG_DEBUG(("SHIFT")); + + if (spho->penultima != SPHO_POS_INVALID) { + picoos_int16 shift; + /* set penultima as new left context and set activeStartPos to the shifted activeEndPos */ + PICODBG_DEBUG(( + "SHIFT shifting penultima from %i to 0", + spho->penultima)); + shift = shift_range_left_1(spho, &spho->penultima, 0); + if (shift < 0) { + picoos_emRaiseException(this->common->em,PICO_ERR_OTHER,NULL,NULL); + return PICODATA_PU_ERROR; + } + spho->activeStartPos = spho->activeEndPos + - shift; + spho->lastPhraseBoundPos -= shift; + spho->suppressParseWordBound = FALSE; + spho->suppressRecombWordBound = FALSE; + + } else { + picoos_int16 shift; + picoos_bool lastPhraseBoundActive; + if (spho->activeStartPos == spho->activeEndPos) { + /* no items consumed; we have to abandon left context */ + spho->activeStartPos = 0; + } + lastPhraseBoundActive = (spho->lastPhraseBoundPos >= spho->activeStartPos); + /* dummy comment */ + PICODBG_DEBUG(("SHIFT shift active end from %i to %i", + spho->activeEndPos, spho->activeStartPos)); + shift = shift_range_left_1(spho, &spho->activeEndPos, spho->activeStartPos); + if (shift < 0) { + picoos_emRaiseException(this->common->em,PICO_ERR_OTHER,NULL,NULL); + return PICODATA_PU_ERROR; + } + if (lastPhraseBoundActive) { + spho->lastPhraseBoundPos -= shift; + } + } + + spho->procState = SPHO_STEPSTATE_INIT; + break; + + default: + picoos_emRaiseException(this->common->em, PICO_ERR_OTHER, NULL, NULL); + return PICODATA_PU_ERROR; + break; + + } /* switch (spho->procState) */ + + } /* while (1) */ + + /* should be never reached */ + picoos_emRaiseException(this->common->em, PICO_ERR_OTHER, NULL, NULL); + return PICODATA_PU_ERROR; +} + +#ifdef __cplusplus +} +#endif + +/* end picospho.c */ diff --git a/pico/lib/picospho.h b/pico/lib/picospho.h new file mode 100644 index 0000000..0c4a0d8 --- /dev/null +++ b/pico/lib/picospho.h @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picospho.h + * + * sentence phonemic/phonetic FSTs PU + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +/** @addtogroup picospho +itemtype, iteminfo1, iteminfo2, content -> TYPE(INFO1,INFO2)content +in the following + +items input +=========== + +processed: + +- WORDPHON(POS,WACC)phon + +- BOUND(BOUNDstrength,BOUNDtype) + + +unprocessed: +- all other item types are forwared through the PU without modification + + + +- POS + a the single, unambiguous POS + +cf. picodata.h for +- WACC (sentence-level accent (aka prominence)) + PICODATA_ACC0 + PICODATA_ACC1 + PICODATA_ACC2 (<- maybe mapped to ACC1, ie. no ACC2 in output) + PICODATA_ACC3 + + +- BOUNDstrength + PICODATA_ITEMINFO1_BOUND_SBEG (sentence start) + PICODATA_ITEMINFO1_BOUND_SEND (at sentence end) + PICODATA_ITEMINFO1_BOUND_TERM (replaces a flush) + PICODATA_ITEMINFO1_BOUND_PHR0 (no break) + PICODATA_ITEMINFO1_BOUND_PHR1 (primary boundary) + PICODATA_ITEMINFO1_BOUND_PHR2 (short break) + PICODATA_ITEMINFO1_BOUND_PHR3 (secondary phrase boundary, no break) + +- BOUNDtype (actually phrase type of the following phrase) + PICODATA_ITEMINFO2_BOUNDTYPE_P (non-terminal phrase) + PICODATA_ITEMINFO2_BOUNDTYPE_T (terminal phrase) + PICODATA_ITEMINFO2_BOUNDTYPE_Q (question terminal phrase) + PICODATA_ITEMINFO2_BOUNDTYPE_E (exclamation terminal phrase) + + +output sequence (without CMDs): + + = { BOUND(BOUND_SBEG,PHRASEtype) BOUND(BOUND_SEND,..)} BOUND(BOUND_TERM,..) + + = { BOUND(BOUND_PHR1|2|3,PHRASEtype) } + + = WORDPHON(POS,ACC)phon { WORDPHON(POS,ACC)phon } + + + +mapping ACC & word-level stress to syllable accent value + + ACC0 prim -> 0 + ACC1 prim -> 1 + ACC2 prim -> 2 + ACC3 prim -> 3 + + ACC0 sec -> 0 + ACC1 sec -> 4 + ACC2 sec -> 4 + ACC3 sec -> 4 + +Mapping of values to FST symbol id (has to identical to the symbol table used when compiling the FST) + +Value FST symbol id +phoneme_id -> phoneme_id + 256 * PICOKFST_PLANE_PHONEMES +POS_id -> POS_id + 256 * PICOKFST_PLANE_POS +phrasetype_id -> phrasetype_id + 256 * PICOKFST_PLANE_PHRASETYPES +accentlevel_id -> accentlevel_id + 256 * PICOKFST_PLANE_ACCENTS + + + + + + + +minimal input size (before processing starts) +================== + +processing (ie. sequencially applying spho transducers to phoneme sequence composed of + - phonemes inside WORDPHON items and + - pseudo-phonemes derived from boundaries and POS) is possible with + +- one phrase, consisting of a sequence of maximal 30 non-PUNC items + terminated by a PUNC item. A PUNC is artificially enforced if + needed to start processing. + +- as long as the internal buffer is empty, non-processed item types + can be processed immediately + + + +items output +============ +- BOUND(BOUNDstrength,BOUNDtype) + + bound strength may be changed by the fsts + + in addition, BOUNDs of BOUNDstrength = PHR0 are inserted to mark word boundaries + +- SYLLPHON(POS,ACC)phon + where POS is only set for the first syllable of a word, otherwise NA + + + + + + +other limitations +================= + + + */ +#ifndef PICOSPHO_H_ +#define PICOSPHO_H_ + +#include "picoos.h" +#include "picodata.h" +#include "picorsrc.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +picodata_ProcessingUnit picospho_newSentPhoUnit( + picoos_MemoryManager mm, + picoos_Common common, + picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, + picorsrc_Voice voice); + +#ifdef __cplusplus +} +#endif + + +#endif /*PICOSPHO_H_*/ diff --git a/pico/lib/picotok.c b/pico/lib/picotok.c new file mode 100644 index 0000000..7748a3f --- /dev/null +++ b/pico/lib/picotok.c @@ -0,0 +1,1577 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picotok.c + * + * tokenizer + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + + +/* ************************************************************/ +/* tokenisation and markup handling */ +/* ************************************************************/ + +/** @addtogroup picotok + @b tokenisation_overview + + markup handling overview: + + The following markups are recognized + - ignore + - speed + - pitch + - volume + - voice + - preproccontext + - mark + - play + - usesig + - genfile + - sentence + - s + - paragraph + - p + - break + - spell (pauses between letter) + - phoneme + + All markups which are recognized but are not yet implemented in pico + system have the mark. +*/ + + +#include "picodefs.h" +#include "picoos.h" +#include "picobase.h" +#include "picodbg.h" +#include "picodata.h" +#include "picotok.h" +#include "picoktab.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +/* *****************************************************************************/ + +#define IN_BUF_SIZE 255 +#define OUT_BUF_SIZE IN_BUF_SIZE + 3 * PICODATA_ITEM_HEADSIZE + 3 + +#define MARKUP_STRING_BUF_SIZE (IN_BUF_SIZE*5) +#define MAX_NR_MARKUP_PARAMS 6 +#define MARKUP_HANDLING_DISABLED 0 +#define MARKUP_HANDLING_ENABLED 1 +#define EOL '\n' + + +typedef picoos_int8 pico_tokenSubType; +typedef picoos_uint8 pico_tokenType; + +/** @todo : consider adding these specialized exception codes: */ + +#define PICO_ERR_MARKUP_VALUE_OUT_OF_RANGE PICO_ERR_OTHER +#define PICO_ERR_INVALID_MARKUP_TAG PICO_ERR_OTHER +#define PICO_ERR_INTERNAL_LIMIT PICO_ERR_OTHER + +typedef enum {MIDummyStart, MIIgnore, + MIPitch, MISpeed, MIVolume, + MIVoice, MIPreprocContext, MIMarker, + MIPlay, MIUseSig, MIGenFile, MIParagraph, + MISentence, MIBreak, MISpell, MIPhoneme, MIItem, MISpeaker, MIDummyEnd + } MarkupId; +typedef enum {MSNotInMarkup, MSGotStart, MSExpectingmarkupTagName, MSInmarkupTagName, + MSGotmarkupTagName, MSInAttrName, MSGotAttrName, MSGotEqual, MSInAttrValue, + MSInAttrValueEscaped, MSGotAttrValue, MSGotEndSlash, MSGotEnd, + MSError, MSErrorTooLong, MSErrorSyntax + } MarkupState; +typedef enum {MENone, MEMissingStart, MEUnknownTag, MEIdent, MEMissingEqual, + MEMissingQuote, MEMissingEnd, MEUnexpectedChar, MEInterprete + } MarkupParseError; + +typedef enum {MTNone, MTStart, MTEnd, MTEmpty} MarkupTagType; + +#define UTF_CHAR_COMPLETE 2 +#define UTF_CHAR_INCOMPLETE 1 +#define UTF_CHAR_MALFORMED 0 + +#define TOK_MARKUP_KW_IGNORE (picoos_uchar*)"ignore" +#define TOK_MARKUP_KW_SPEED (picoos_uchar*)"speed" +#define TOK_MARKUP_KW_PITCH (picoos_uchar*)"pitch" +#define TOK_MARKUP_KW_VOLUME (picoos_uchar*)"volume" +#define TOK_MARKUP_KW_VOICE (picoos_uchar*)"voice" +#define TOK_MARKUP_KW_CONTEXT (picoos_uchar*)"preproccontext" +#define TOK_MARKUP_KW_MARK (picoos_uchar*)"mark" +#define TOK_MARKUP_KW_PLAY (picoos_uchar*)"play" +#define TOK_MARKUP_KW_USESIG (picoos_uchar*)"usesig" +#define TOK_MARKUP_KW_GENFILE (picoos_uchar*)"genfile" +#define TOK_MARKUP_KW_SENTENCE (picoos_uchar*)"sentence" +#define TOK_MARKUP_KW_S (picoos_uchar*)"s" +#define TOK_MARKUP_KW_PARAGRAPH (picoos_uchar*)"paragraph" +#define TOK_MARKUP_KW_P (picoos_uchar*)"p" +#define TOK_MARKUP_KW_BREAK (picoos_uchar*)"break" +#define TOK_MARKUP_KW_SPELL (picoos_uchar*)"spell" +#define TOK_MARKUP_KW_PHONEME (picoos_uchar*)"phoneme" +#define TOK_MARKUP_KW_ITEM (picoos_uchar*)"item" +#define TOK_MARKUP_KW_SPEAKER (picoos_uchar*)"speaker" + +#define KWLevel (picoos_uchar *)"level" +#define KWName (picoos_uchar *)"name" +#define KWProsDomain (picoos_uchar *)"prosodydomain" +#define KWTime (picoos_uchar *)"time" +#define KWMode (picoos_uchar *)"mode" +#define KWSB (picoos_uchar *)"sb" +#define KWPB (picoos_uchar *)"pb" +#define KWFile (picoos_uchar *)"file" +#define KWType (picoos_uchar *)"type" +#define KWF0Beg (picoos_uchar *)"f0beg" +#define KWF0End (picoos_uchar *)"f0end" +#define KWXFadeBeg (picoos_uchar *)"xfadebeg" +#define KWXFadeEnd (picoos_uchar *)"xfadeend" +#define KWAlphabet (picoos_uchar *)"alphabet" +#define KWPH (picoos_uchar *)"ph" +#define KWOrthMode (picoos_uchar *)"orthmode" +#define KWIgnorePunct (picoos_uchar *)"ignorepunct" +#define KWInfo1 (picoos_uchar *)"info1" +#define KWInfo2 (picoos_uchar *)"info2" +#define KWDATA (picoos_uchar *)"data" + +#define PICO_SPEED_MIN 20 +#define PICO_SPEED_MAX 500 +#define PICO_SPEED_DEFAULT 100 +#define PICO_SPEED_FACTOR_MIN 500 +#define PICO_SPEED_FACTOR_MAX 2000 + +#define PICO_PITCH_MIN 50 +#define PICO_PITCH_MAX 200 +#define PICO_PITCH_DEFAULT 100 +#define PICO_PITCH_FACTOR_MIN 500 +#define PICO_PITCH_FACTOR_MAX 2000 +#define PICO_PITCH_ADD_MIN -100 +#define PICO_PITCH_ADD_MAX 100 +#define PICO_PITCH_ADD_DEFAULT 0 + +#define PICO_VOLUME_MIN 0 +#define PICO_VOLUME_MAX 500 +#define PICO_VOLUME_DEFAULT 100 +#define PICO_VOLUME_FACTOR_MIN 500 +#define PICO_VOLUME_FACTOR_MAX 2000 + +#define PICO_SPEAKER_MIN 20 +#define PICO_SPEAKER_MAX 180 +#define PICO_SPEAKER_DEFAULT 100 +#define PICO_SPEAKER_FACTOR_MIN 500 +#define PICO_SPEAKER_FACTOR_MAX 2000 + +#define PICO_CONTEXT_DEFAULT (picoos_uchar*)"DEFAULT" + +#define PARAGRAPH_PAUSE_DUR 500 +#define SPELL_WITH_PHRASE_BREAK 1 +#define SPELL_WITH_SENTENCE_BREAK 2 + +/* *****************************************************************************/ + +#define TOK_PUNC_FLUSH (picoos_char) '\0' + +typedef picoos_uchar Word[MARKUP_STRING_BUF_SIZE]; + + +struct MarkupParam { + Word paramId; + Word paramVal; +}; + +typedef struct MarkupParam MarkupParams[MAX_NR_MARKUP_PARAMS]; + +typedef picoos_uchar utf8char0c[5]; /* one more than needed so it is ended always with 0c*/ + +/** subobject : TokenizeUnit + * shortcut : tok + */ +typedef struct tok_subobj +{ + picoos_int32 ignLevel; + + utf8char0c utf; + picoos_int32 utfpos; + picoos_int32 utflen; + + MarkupParams markupParams; + picoos_int32 nrMarkupParams; + MarkupState markupState; + picoos_uchar markupStr[MARKUP_STRING_BUF_SIZE]; + picoos_int32 markupPos; + picoos_int32 markupLevel[MIDummyEnd+1]; + picoos_uchar markupTagName[IN_BUF_SIZE]; + MarkupTagType markupTagType; + MarkupParseError markupTagErr; + + picoos_int32 strPos; + picoos_uchar strDelim; + picoos_bool isFileAttr; + + pico_tokenType tokenType; + pico_tokenSubType tokenSubType; + + picoos_int32 tokenPos; + picoos_uchar tokenStr[IN_BUF_SIZE]; + + picoos_int32 nrEOL; + + picoos_bool markupHandlingMode; /* to be moved ??? */ + picoos_bool aborted; /* to be moved ??? */ + + picoos_bool start; + + picoos_uint8 outBuf[OUT_BUF_SIZE]; /* internal output buffer */ + picoos_uint16 outReadPos; /* next pos to read from outBuf */ + picoos_uint16 outWritePos; /* next pos to write to outBuf */ + + picoos_uchar saveFile[IN_BUF_SIZE]; + Word phonemes; + + picotrns_SimpleTransducer transducer; + + /* kbs */ + + picoktab_Graphs graphTab; + picokfst_FST xsampa_parser; + picokfst_FST svoxpa_parser; + picokfst_FST xsampa2svoxpa_mapper; + + + +} tok_subobj_t; + +/* *****************************************************************************/ + +static void tok_treatMarkupAsSimpleToken (picodata_ProcessingUnit this, tok_subobj_t * tok); +static void tok_treatChar (picodata_ProcessingUnit this, tok_subobj_t * tok, picoos_uchar ch, picoos_bool markupHandling); +static void tok_treatMarkup (picodata_ProcessingUnit this, tok_subobj_t * tok); +static void tok_putToMarkup (picodata_ProcessingUnit this, tok_subobj_t * tok, picoos_uchar str[]); +static void tok_treatSimpleToken (picodata_ProcessingUnit this, tok_subobj_t * tok); +static MarkupId tok_markupTagId (picoos_uchar tagId[]); + +/* *****************************************************************************/ + +static picoos_bool tok_strEqual(picoos_uchar * str1, picoos_uchar * str2) +{ + return (picoos_strcmp((picoos_char*)str1, (picoos_char*)str2) == 0); +} + +static void tok_reduceBlanks(picoos_uchar * str) + /* Remove leading and trailing blanks of 'str' and reduce + groups of blanks within string to exactly one blank. */ + +{ + int i = 0; + int j = 0; + + while (str[j] != 0) { + if (str[j] == (picoos_uchar)' ') { + /* note one blank except at the beginning of string */ + if (i > 0) { + str[i] = (picoos_uchar)' '; + i++; + } + j++; + while (str[j] == (picoos_uchar)' ') { + j++; + } + } else { + str[i] = str[j]; + j++; + i++; + } + } + + /* remove blanks at end of string */ + if ((i > 0) && (str[i - 1] == ' ')) { + i--; + } + str[i] = 0; +} + + +static void tok_startIgnore (tok_subobj_t * tok) +{ + tok->ignLevel++; +} + + +static void tok_endIgnore (tok_subobj_t * tok) +{ + if (tok->ignLevel > 0) { + tok->ignLevel--; + } +} + + +static void tok_getParamIntVal (MarkupParams params, picoos_uchar paramId[], picoos_int32 * paramVal, picoos_bool * paramFound) +{ + int i=0; + + while ((i < MAX_NR_MARKUP_PARAMS) && !tok_strEqual(paramId,params[i].paramId)) { + i++; + } + if ((i < MAX_NR_MARKUP_PARAMS)) { + (*paramVal) = picoos_atoi((picoos_char*)params[i].paramVal); + (*paramFound) = TRUE; + } else { + (*paramVal) = -1; + (*paramFound) = FALSE; + } +} + + + +static void tok_getParamStrVal (MarkupParams params, picoos_uchar paramId[], picoos_uchar paramStrVal[], picoos_bool * paramFound) +{ + int i=0; + + while ((i < MAX_NR_MARKUP_PARAMS) && !tok_strEqual(paramId,params[i].paramId)) { + i++; + } + if (i < MAX_NR_MARKUP_PARAMS) { + picoos_strcpy((picoos_char*)paramStrVal, (picoos_char*)params[i].paramVal); + (*paramFound) = TRUE; + } else { + paramStrVal[0] = 0; + (*paramFound) = FALSE; + } +} + + +static void tok_getParamPhonesStr (MarkupParams params, picoos_uchar paramId[], picoos_uchar alphabet[], picoos_uchar phones[], picoos_int32 phoneslen, picoos_bool * paramFound) +{ + + int i; + picoos_bool done; + + i = 0; + while ((i < MAX_NR_MARKUP_PARAMS) && !tok_strEqual(paramId, params[i].paramId)) { + i++; + } + if (i < MAX_NR_MARKUP_PARAMS) { + if (tok_strEqual(alphabet, PICODATA_XSAMPA) || tok_strEqual(alphabet, (picoos_uchar*)"")) { + picoos_strlcpy((picoos_char*)phones, (picoos_char*)params[i].paramVal, phoneslen); + done = TRUE; + } else { + done = FALSE; + } + (*paramFound) = TRUE; + } else { + done = FALSE; + (*paramFound) = FALSE; + } + if (!done) { + phones[0] = 0; + } +} + + +static void tok_clearMarkupParams (MarkupParams params) +{ + int i; + + for (i = 0; i= '0') && (durStr[i] <= '9')) { + num = 10 * num + (int)durStr[i] - (int)'0'; + tmpWord[i] = ' '; + i++; + } + tok_reduceBlanks(tmpWord); + if (tok_strEqual(tmpWord, (picoos_uchar*)"s")) { + (*dur) = (1000 * num); + (*done) = TRUE; + } else if (tok_strEqual(tmpWord,(picoos_uchar*)"ms")) { + (*dur) = num; + (*done) = TRUE; + } else { + (*dur) = 0; + (*done) = FALSE; + } +} + + +static picoos_int32 tok_putToUtf (tok_subobj_t * tok, picoos_uchar ch) +{ + if (tok->utfpos < PICOBASE_UTF8_MAXLEN) { + tok->utf[tok->utfpos] = ch; + if (tok->utfpos == 0) { + tok->utflen = picobase_det_utf8_length(ch); + } else if (((ch < (picoos_uchar)'\200') || (ch >= (picoos_uchar)'\300'))) { + tok->utflen = 0; + } + (tok->utfpos)++; + if (tok->utfpos == tok->utflen) { + if ((tok->utfpos < PICOBASE_UTF8_MAXLEN)) { + tok->utf[tok->utfpos] = 0; + } + return UTF_CHAR_COMPLETE; + } else if (tok->utfpos < tok->utflen) { + return UTF_CHAR_INCOMPLETE; + } else { + return UTF_CHAR_MALFORMED; + } + } else { + return UTF_CHAR_MALFORMED; + } +} + + +static picoos_bool tok_isRelative (picoos_uchar strval[], picoos_uint32 * val) +{ + picoos_int32 len; + picoos_bool rel; + + rel = FALSE; + len = picoos_strlen((picoos_char*)strval); + if (len > 0) { + if (strval[len - 1] == '%') { + strval[len - 1] = 0; + if ((strval[0] == '+') || (strval[0] == '-')) { + (*val) = 1000 + (picoos_atoi((picoos_char*)strval) * 10); + } else { + (*val) = picoos_atoi((picoos_char*)strval) * 10; + } + rel = TRUE; + } + } + return rel; +} + + +static void tok_putItem (picodata_ProcessingUnit this, tok_subobj_t * tok, + picoos_uint8 itemType, picoos_uint8 info1, picoos_uint8 info2, + picoos_uint16 val, + picoos_uchar str[]) +{ + picoos_int32 len, i; + + if ((itemType == PICODATA_ITEM_CMD) && (info1 == PICODATA_ITEMINFO1_CMD_FLUSH)) { + tok->outBuf[tok->outWritePos++] = itemType; + tok->outBuf[tok->outWritePos++] = info1; + tok->outBuf[tok->outWritePos++] = info2; + tok->outBuf[tok->outWritePos++] = 0; + } + else if (tok->ignLevel <= 0) { + switch (itemType) { + case PICODATA_ITEM_CMD: + switch (info1) { + case PICODATA_ITEMINFO1_CMD_CONTEXT: + case PICODATA_ITEMINFO1_CMD_VOICE: + case PICODATA_ITEMINFO1_CMD_MARKER: + case PICODATA_ITEMINFO1_CMD_PLAY: + case PICODATA_ITEMINFO1_CMD_SAVE: + case PICODATA_ITEMINFO1_CMD_UNSAVE: + case PICODATA_ITEMINFO1_CMD_PROSDOMAIN: + case PICODATA_ITEMINFO1_CMD_PHONEME: + len = picoos_strlen((picoos_char*)str); + if (tok->outWritePos + 4 + len < OUT_BUF_SIZE) { + tok->outBuf[tok->outWritePos++] = itemType; + tok->outBuf[tok->outWritePos++] = info1; + tok->outBuf[tok->outWritePos++] = info2; + tok->outBuf[tok->outWritePos++] = len; + for (i=0; ioutBuf[tok->outWritePos++] = str[i]; + } + } + else { + PICODBG_WARN(("tok_putItem: output buffer too small")); + } + break; + case PICODATA_ITEMINFO1_CMD_IGNSIG: + case PICODATA_ITEMINFO1_CMD_IGNORE: + if (tok->outWritePos + 4 < OUT_BUF_SIZE) { + tok->outBuf[tok->outWritePos++] = itemType; + tok->outBuf[tok->outWritePos++] = info1; + tok->outBuf[tok->outWritePos++] = info2; + tok->outBuf[tok->outWritePos++] = 0; + } + else { + PICODBG_WARN(("tok_putItem: output buffer too small")); + } + break; + case PICODATA_ITEMINFO1_CMD_SPEED: + case PICODATA_ITEMINFO1_CMD_PITCH: + case PICODATA_ITEMINFO1_CMD_VOLUME: + case PICODATA_ITEMINFO1_CMD_SPELL: + case PICODATA_ITEMINFO1_CMD_SIL: + case PICODATA_ITEMINFO1_CMD_SPEAKER: + if (tok->outWritePos + 4 + 2 < OUT_BUF_SIZE) { + tok->outBuf[tok->outWritePos++] = itemType; + tok->outBuf[tok->outWritePos++] = info1; + tok->outBuf[tok->outWritePos++] = info2; + tok->outBuf[tok->outWritePos++] = 2; + tok->outBuf[tok->outWritePos++] = val % 256; + tok->outBuf[tok->outWritePos++] = val / 256; + } + else { + PICODBG_WARN(("tok_putItem: output buffer too small")); + } + break; + default: + PICODBG_WARN(("tok_putItem: unknown command type")); + } + break; + case PICODATA_ITEM_TOKEN: + len = picoos_strlen((picoos_char*)str); + if (tok->outWritePos + 4 + len < OUT_BUF_SIZE) { + tok->outBuf[tok->outWritePos++] = itemType; + tok->outBuf[tok->outWritePos++] = info1; + tok->outBuf[tok->outWritePos++] = info2; + tok->outBuf[tok->outWritePos++] = len; + for (i=0; ioutBuf[tok->outWritePos++] = str[i]; + } + } + else { + PICODBG_WARN(("tok_putItem: output buffer too small")); + } + break; + default: + PICODBG_WARN(("tok_putItem: unknown item type")); + } + } +} + + +static void tok_putItem2 (picodata_ProcessingUnit this, tok_subobj_t * tok, + picoos_uint8 type, + picoos_uint8 info1, picoos_uint8 info2, + picoos_uint8 len, + picoos_uint8 data[]) +{ + picoos_int32 i; + + if (is_valid_itemtype(type)) { + tok->outBuf[tok->outWritePos++] = type; + tok->outBuf[tok->outWritePos++] = info1; + tok->outBuf[tok->outWritePos++] = info2; + tok->outBuf[tok->outWritePos++] = len; + for (i=0; ioutBuf[tok->outWritePos++] = data[i]; + } + } +} + + +static MarkupId tok_markupTagId (picoos_uchar tagId[]) +{ + if (picoos_strstr(tagId,(picoos_char *)"svox:") == (picoos_char *)tagId) { + tagId+=5; + } + if (tok_strEqual(tagId, TOK_MARKUP_KW_IGNORE)) { + return MIIgnore; + } else if (tok_strEqual(tagId, TOK_MARKUP_KW_SPEED)) { + return MISpeed; + } else if (tok_strEqual(tagId, TOK_MARKUP_KW_PITCH)) { + return MIPitch; + } else if (tok_strEqual(tagId, TOK_MARKUP_KW_VOLUME)) { + return MIVolume; + } else if (tok_strEqual(tagId, TOK_MARKUP_KW_SPEAKER)) { + return MISpeaker; + } else if (tok_strEqual(tagId, TOK_MARKUP_KW_VOICE)) { + return MIVoice; + } else if (tok_strEqual(tagId, TOK_MARKUP_KW_CONTEXT)) { + return MIPreprocContext; + } else if (tok_strEqual(tagId, TOK_MARKUP_KW_MARK)) { + return MIMarker; + } else if (tok_strEqual(tagId, TOK_MARKUP_KW_PLAY)) { + return MIPlay; + } else if (tok_strEqual(tagId, TOK_MARKUP_KW_USESIG)) { + return MIUseSig; + } else if (tok_strEqual(tagId, TOK_MARKUP_KW_GENFILE)) { + return MIGenFile; + } else if (tok_strEqual(tagId, TOK_MARKUP_KW_SENTENCE) || tok_strEqual(tagId, TOK_MARKUP_KW_S)) { + return MISentence; + } else if (tok_strEqual(tagId, TOK_MARKUP_KW_PARAGRAPH) || tok_strEqual(tagId, TOK_MARKUP_KW_P)) { + return MIParagraph; + } else if (tok_strEqual(tagId, TOK_MARKUP_KW_BREAK)) { + return MIBreak; + } else if (tok_strEqual(tagId, TOK_MARKUP_KW_SPELL)) { + return MISpell; + } else if (tok_strEqual(tagId, TOK_MARKUP_KW_PHONEME)) { + return MIPhoneme; + } else if (tok_strEqual(tagId, TOK_MARKUP_KW_ITEM)) { + return MIItem; + } else { + return MIDummyEnd; + } +} + + +static void tok_checkLimits (picodata_ProcessingUnit this, picoos_uint32 * value, picoos_uint32 min, picoos_uint32 max, picoos_uchar valueType[]) +{ + if ((((*value) < min) || ((*value) > max))) { + picoos_emRaiseWarning(this->common->em, PICO_ERR_MARKUP_VALUE_OUT_OF_RANGE, (picoos_char*)"", (picoos_char*)"attempt to set illegal value %i for %s", *value, valueType); + if (((*value) < min)) { + (*value) = min; + } else if (((*value) > max)) { + (*value) = max; + } + } +} + + + +/* + +static void tok_checkRealLimits (picodata_ProcessingUnit this, picoos_single * value, picoos_single min, picoos_single max, picoos_uchar valueType[]) +{ + if ((((*value) < min) || ((*value) > max))) { + picoos_emRaiseWarning(this->common->em, PICO_ERR_MARKUP_VALUE_OUT_OF_RANGE, (picoos_char*)"", (picoos_char*)"attempt to set illegal value %f for %s", *value, valueType); + if (((*value) < min)) { + (*value) = min; + } else if (((*value) > max)) { + (*value) = max; + } + } +} +*/ + +#define VAL_STR_LEN 21 + +static void tok_interpretMarkup (picodata_ProcessingUnit this, tok_subobj_t * tok, picoos_bool isStartTag, MarkupId mId) +{ + picoos_bool done; + picoos_int32 ival; + picoos_uint32 uval; + picoos_int32 ival2; + picoos_uchar valStr[VAL_STR_LEN]; + picoos_uchar valStr2[VAL_STR_LEN]; + picoos_uchar valStr3[VAL_STR_LEN]; + picoos_int32 i2; + picoos_uint32 dur; + picoos_bool done1; + picoos_bool paramFound; + picoos_uint8 type, info1, info2; + picoos_uint8 data[256]; + picoos_int32 pos, n, len; + picoos_uchar part[10]; + + done = FALSE; + switch (mId) { + case MIIgnore: + if (isStartTag && tok_strEqual(tok->markupParams[0].paramId,(picoos_uchar*)"")) { + tok_startIgnore(tok); + done = TRUE; + } else if (!isStartTag && tok_strEqual(tok->markupParams[0].paramId, (picoos_uchar*)"")) { + tok_endIgnore(tok); + done = TRUE; + } + break; + case MISpeed: + if (isStartTag && tok_strEqual(tok->markupParams[0].paramId, KWLevel)) { + if (tok_isRelative(tok->markupParams[0].paramVal, & uval)) { + tok_checkLimits(this, & uval, PICO_SPEED_FACTOR_MIN, PICO_SPEED_FACTOR_MAX,(picoos_uchar*)"relative speed factor"); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_SPEED, PICODATA_ITEMINFO2_CMD_RELATIVE, uval, (picoos_uchar*)""); + } else { + uval = picoos_atoi((picoos_char*)tok->markupParams[0].paramVal); + tok_checkLimits(this, & uval, PICO_SPEED_MIN, PICO_SPEED_MAX,(picoos_uchar*)"speed"); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_SPEED, PICODATA_ITEMINFO2_CMD_ABSOLUTE, uval, (picoos_uchar*)""); + } + done = TRUE; + } else if (!isStartTag && tok_strEqual(tok->markupParams[0].paramId, (picoos_uchar*)"")) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_SPEED, PICODATA_ITEMINFO2_CMD_ABSOLUTE, PICO_SPEED_DEFAULT, (picoos_uchar*)""); + done = TRUE; + } + break; + case MIPitch: + if (isStartTag && tok_strEqual(tok->markupParams[0].paramId, KWLevel)) { + if (tok_isRelative(tok->markupParams[0].paramVal, & uval)) { + tok_checkLimits(this, & uval,PICO_PITCH_FACTOR_MIN,PICO_PITCH_FACTOR_MAX, (picoos_uchar*)"relative pitch factor"); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_PITCH, PICODATA_ITEMINFO2_CMD_RELATIVE, uval, (picoos_uchar*)""); + } else { + uval = picoos_atoi((picoos_char*)tok->markupParams[0].paramVal); + tok_checkLimits(this, & uval,PICO_PITCH_MIN,PICO_PITCH_MAX, (picoos_uchar*)"pitch"); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_PITCH,PICODATA_ITEMINFO2_CMD_ABSOLUTE, uval, (picoos_uchar*)""); + } + done = TRUE; + } else if (!isStartTag && tok_strEqual(tok->markupParams[0].paramId, (picoos_uchar*)"")) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_PITCH,PICODATA_ITEMINFO2_CMD_ABSOLUTE, PICO_PITCH_DEFAULT, (picoos_uchar*)""); + done = TRUE; + } + break; + case MIVolume: + if (isStartTag && tok_strEqual(tok->markupParams[0].paramId, KWLevel)) { + if (tok_isRelative(tok->markupParams[0].paramVal, & uval)) { + tok_checkLimits(this, & uval, PICO_VOLUME_FACTOR_MIN, PICO_VOLUME_FACTOR_MAX, (picoos_uchar*)"relative volume factor"); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_VOLUME, PICODATA_ITEMINFO2_CMD_RELATIVE, uval, (picoos_uchar*)""); + } else { + uval = picoos_atoi((picoos_char*)tok->markupParams[0].paramVal); + tok_checkLimits(this, & uval, PICO_VOLUME_MIN, PICO_VOLUME_MAX, (picoos_uchar*)"volume"); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_VOLUME, PICODATA_ITEMINFO2_CMD_ABSOLUTE, uval, (picoos_uchar*)""); + } + done = TRUE; + } else if (!isStartTag && tok_strEqual(tok->markupParams[0].paramId, (picoos_uchar*)"")) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_VOLUME, PICODATA_ITEMINFO2_CMD_ABSOLUTE, PICO_VOLUME_DEFAULT, (picoos_uchar*)""); + done = TRUE; + } + break; + case MISpeaker: + if (isStartTag && tok_strEqual(tok->markupParams[0].paramId, KWLevel)) { + if (tok_isRelative(tok->markupParams[0].paramVal, & uval)) { + tok_checkLimits(this, & uval, PICO_SPEAKER_FACTOR_MIN, PICO_SPEAKER_FACTOR_MAX, (picoos_uchar*)"relative speaker factor"); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_SPEAKER, PICODATA_ITEMINFO2_CMD_RELATIVE, uval, (picoos_uchar*)""); + } else { + uval = picoos_atoi((picoos_char*)tok->markupParams[0].paramVal); + tok_checkLimits(this, & uval, PICO_SPEAKER_MIN, PICO_SPEAKER_MAX, (picoos_uchar*)"speaker"); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_SPEAKER, PICODATA_ITEMINFO2_CMD_ABSOLUTE, uval, (picoos_uchar*)""); + } + done = TRUE; + } else if (!isStartTag && tok_strEqual(tok->markupParams[0].paramId, (picoos_uchar*)"")) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_SPEAKER, PICODATA_ITEMINFO2_CMD_ABSOLUTE, PICO_SPEAKER_DEFAULT, (picoos_uchar*)""); + done = TRUE; + } + break; + + case MIVoice: + if (isStartTag && tok_strEqual(tok->markupParams[0].paramId, KWName)) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_VOICE, PICODATA_ITEMINFO2_NA, 0, tok->markupParams[0].paramVal); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_FLUSH, PICODATA_ITEMINFO2_NA, 0, (picoos_uchar*)""); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_PROSDOMAIN, 0, 0, (picoos_uchar*)""); + done = TRUE; + } else if (!isStartTag && tok_strEqual(tok->markupParams[0].paramId,(picoos_uchar*)"")) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_VOICE, PICODATA_ITEMINFO2_NA, 0, (picoos_uchar*)""); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_FLUSH, PICODATA_ITEMINFO2_NA, 0, (picoos_uchar*)""); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_PROSDOMAIN, 0, 0, (picoos_uchar*)""); + done = TRUE; + } + break; + case MIPreprocContext: + if (isStartTag && tok_strEqual(tok->markupParams[0].paramId, KWName)) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_CONTEXT, PICODATA_ITEMINFO2_NA, 0, tok->markupParams[0].paramVal); + done = TRUE; + } else if (!isStartTag && tok_strEqual(tok->markupParams[0].paramId,(picoos_uchar*)"")) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_CONTEXT, PICODATA_ITEMINFO2_NA, 0, PICO_CONTEXT_DEFAULT); + done = TRUE; + } + break; + case MIMarker: + if (isStartTag && tok_strEqual(tok->markupParams[0].paramId, KWName)) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_MARKER, PICODATA_ITEMINFO2_NA, 0, tok->markupParams[0].paramVal); + done = TRUE; + } else if (!isStartTag && tok_strEqual(tok->markupParams[0].paramId,(picoos_uchar*)"")) { + done = TRUE; + } + break; + case MISentence: + if (isStartTag) { + tok_getParamStrVal(tok->markupParams, KWProsDomain, (picoos_uchar*)valStr, & paramFound); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_FLUSH, PICODATA_ITEMINFO2_NA, 0, (picoos_uchar*)""); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_PROSDOMAIN, 2, 0, valStr); + done = TRUE; + } else if (!isStartTag && tok_strEqual(tok->markupParams[0].paramId, (picoos_uchar*)"")) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_FLUSH, PICODATA_ITEMINFO2_NA, 0, (picoos_uchar*)""); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_PROSDOMAIN, 2, 0, (picoos_uchar*)""); + done = TRUE; + } + break; + case MIParagraph: + if (isStartTag) { + tok_getParamStrVal(tok->markupParams, KWProsDomain, (picoos_uchar*)valStr, & paramFound); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_FLUSH, PICODATA_ITEMINFO2_NA, 0, (picoos_uchar*)""); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_PROSDOMAIN, 1, 0, valStr); + done = TRUE; + } else if (!isStartTag && tok_strEqual(tok->markupParams[0].paramId, (picoos_uchar*)"")) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_FLUSH, PICODATA_ITEMINFO2_NA, 0, (picoos_uchar*)""); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_SIL, PICODATA_ITEMINFO2_NA, PARAGRAPH_PAUSE_DUR, (picoos_uchar*)""); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_PROSDOMAIN, 1, 0, (picoos_uchar*)""); + done = TRUE; + } + break; + case MIBreak: + if (isStartTag && tok_strEqual(tok->markupParams[0].paramId, KWTime)) { + tok_getDur(tok->markupParams[0].paramVal, & dur, & done1); + tok_checkLimits (this, &dur, 0, 65535, (picoos_uchar*)"time"); + if (done1) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_SIL, PICODATA_ITEMINFO2_NA, dur, (picoos_uchar*)""); + done = TRUE; + } + } else if (!isStartTag && tok_strEqual(tok->markupParams[0].paramId, (picoos_uchar*)"")) { + done = TRUE; + } + break; + case MISpell: + if (isStartTag) { + if (tok_strEqual(tok->markupParams[0].paramId, KWMode)) { + if (tok_strEqual(tok->markupParams[0].paramVal, KWPB)) { + uval = SPELL_WITH_PHRASE_BREAK; + } else if (tok_strEqual(tok->markupParams[0].paramVal, KWSB)) { + uval = SPELL_WITH_SENTENCE_BREAK; + } else { + tok_getDur(tok->markupParams[0].paramVal, & uval, & done1); + tok_checkLimits (this, & uval, 0, 65535, (picoos_uchar*)"time"); + if (done1) { + done = TRUE; + } + } + } else { + uval = SPELL_WITH_PHRASE_BREAK; + } + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_SPELL, PICODATA_ITEMINFO2_CMD_START, uval, (picoos_uchar*)""); + done = TRUE; + } else if (!isStartTag && tok_strEqual(tok->markupParams[0].paramId, (picoos_uchar*)"")) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_SPELL, PICODATA_ITEMINFO2_CMD_END, 0, (picoos_uchar*)""); + done = TRUE; + } + break; + case MIGenFile: + if (isStartTag && tok_strEqual(tok->markupParams[0].paramId, KWFile)) { + if (tok->saveFile[0] != 0) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_UNSAVE, + picodata_getPuTypeFromExtension(tok->saveFile, /*input*/FALSE), 0, tok->saveFile); + tok->saveFile[0] = 0; + } + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_SAVE, + picodata_getPuTypeFromExtension(tok->markupParams[0].paramVal, /*input*/FALSE), 0, tok->markupParams[0].paramVal); + picoos_strcpy((picoos_char*)tok->saveFile, (picoos_char*)tok->markupParams[0].paramVal); + done = TRUE; + } else if (!isStartTag && tok_strEqual(tok->markupParams[0].paramId, (picoos_uchar*)"")) { + if (tok->saveFile[0] != 0) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_UNSAVE, + picodata_getPuTypeFromExtension(tok->saveFile, /*input*/FALSE), 0, (picoos_uchar*)""); + tok->saveFile[0] = 0; + } + done = TRUE; + } + break; + case MIPlay: + if (isStartTag && tok_strEqual(tok->markupParams[0].paramId, KWFile)) { + if (picoos_FileExists(this->common, (picoos_char*)tok->markupParams[0].paramVal)) { + tok_getParamIntVal(tok->markupParams,KWF0Beg,& ival,& paramFound); + tok_getParamIntVal(tok->markupParams,KWF0End,& ival2,& paramFound); + tok_getParamStrVal(tok->markupParams,KWAlphabet,valStr3,& paramFound); + tok_getParamPhonesStr(tok->markupParams,KWXFadeBeg,valStr3,valStr,VAL_STR_LEN,& paramFound); + tok_getParamPhonesStr(tok->markupParams,KWXFadeEnd,valStr3,valStr2,VAL_STR_LEN,& paramFound); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_PLAY, + picodata_getPuTypeFromExtension(tok->markupParams[0].paramVal, /*input*/TRUE), 0, tok->markupParams[0].paramVal); + tok_startIgnore(tok); + } else { + if (tok->ignLevel > 0) { + tok_startIgnore(tok); + } else { + picoos_emRaiseWarning(this->common->em, PICO_EXC_CANT_OPEN_FILE, (picoos_char*)"", (picoos_char*)"file '%s' not found; synthesizing enclosed text instead\n", tok->markupParams[0].paramVal); + } + } + done = TRUE; + } else if (!isStartTag && tok_strEqual(tok->markupParams[0].paramId, (picoos_uchar*)"")) { + tok_endIgnore(tok); + done = TRUE; + } + break; + case MIUseSig: + if (isStartTag && tok_strEqual(tok->markupParams[0].paramId, KWFile)) { + if (picoos_FileExists(this->common, (picoos_char*)tok->markupParams[0].paramVal)) { + tok_getParamIntVal(tok->markupParams,KWF0Beg,& ival,& paramFound); + tok_getParamIntVal(tok->markupParams,KWF0End,& ival2,& paramFound); + tok_getParamStrVal(tok->markupParams,KWAlphabet,valStr3, & paramFound); + tok_getParamPhonesStr(tok->markupParams,KWXFadeBeg,valStr3,valStr,VAL_STR_LEN,& paramFound); + tok_getParamPhonesStr(tok->markupParams,KWXFadeEnd,valStr3,valStr2,VAL_STR_LEN,& paramFound); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_PLAY, + picodata_getPuTypeFromExtension(tok->markupParams[0].paramVal, /*input*/TRUE), 0, tok->markupParams[0].paramVal); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_IGNSIG, PICODATA_ITEMINFO2_CMD_START, 0, (picoos_uchar*)""); + } else { + if (tok->ignLevel <= 0) { + picoos_emRaiseWarning(this->common->em, PICO_EXC_CANT_OPEN_FILE, (picoos_char*)"", (picoos_char*)"file '%s' not found; synthesizing enclosed text instead", tok->markupParams[0].paramVal); + } + } + done = TRUE; + } else if (!isStartTag && tok_strEqual(tok->markupParams[0].paramId, (picoos_uchar*)"")) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_IGNSIG, PICODATA_ITEMINFO2_CMD_END, 0, (picoos_uchar*)""); + done = TRUE; + } + break; + case MIPhoneme: + i2 = 0; + if (isStartTag) { + if (tok_strEqual(tok->markupParams[0].paramId, KWAlphabet) && tok_strEqual(tok->markupParams[1].paramId, KWPH)) { + if (tok_strEqual(tok->markupParams[2].paramId, KWOrthMode) + && tok_strEqual(tok->markupParams[2].paramVal, KWIgnorePunct)) { + i2 = 1; + } + if (picodata_mapPAStrToPAIds(tok->transducer, this->common, tok->xsampa_parser, tok->svoxpa_parser, tok->xsampa2svoxpa_mapper, tok->markupParams[1].paramVal, tok->markupParams[0].paramVal, tok->phonemes, sizeof(tok->phonemes)-1) == PICO_OK) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_PHONEME, + PICODATA_ITEMINFO2_CMD_START, i2, tok->phonemes); + done = TRUE; + } else { + PICODBG_WARN(("cannot map phonetic string '%s'; synthesizeing text instead", tok->markupParams[1].paramVal)); + picoos_emRaiseWarning(this->common->em, PICO_ERR_MARKUP_VALUE_OUT_OF_RANGE,(picoos_char*)"", (picoos_char*)"cannot map phonetic string '%s'; synthesizeing text instead", tok->markupParams[1].paramVal); + done = TRUE; + } + } else if (tok_strEqual(tok->markupParams[0].paramId, KWPH)) { + if (tok_strEqual(tok->markupParams[1].paramId, KWOrthMode) + && tok_strEqual(tok->markupParams[1].paramVal, KWIgnorePunct)) { + i2 = 1; + } + if (picodata_mapPAStrToPAIds(tok->transducer, this->common, tok->xsampa_parser, tok->svoxpa_parser, tok->xsampa2svoxpa_mapper, tok->markupParams[0].paramVal, PICODATA_XSAMPA, tok->phonemes, sizeof(tok->phonemes)) == PICO_OK) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_PHONEME, + PICODATA_ITEMINFO2_CMD_START, i2, tok->phonemes); + done = TRUE; + } + else { + PICODBG_WARN(("cannot map phonetic string '%s'; synthesizeing text instead", tok->markupParams[1].paramVal)); + picoos_emRaiseWarning(this->common->em, PICO_ERR_MARKUP_VALUE_OUT_OF_RANGE,(picoos_char*)"", (picoos_char*)"cannot map phonetic string '%s'; synthesizing text instead", tok->markupParams[0].paramVal); + done = TRUE; + } + } + } else if (!isStartTag && tok_strEqual(tok->markupParams[0].paramId, (picoos_uchar*)"")) { + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_PHONEME, + PICODATA_ITEMINFO2_CMD_END, i2, (picoos_uchar*)""); + done = TRUE; + } + break; + case MIItem: + if (isStartTag && tok_strEqual(tok->markupParams[0].paramId, KWType) && + tok_strEqual(tok->markupParams[1].paramId, KWInfo1)&& + tok_strEqual(tok->markupParams[2].paramId, KWInfo2)&& + tok_strEqual(tok->markupParams[3].paramId, KWDATA)) { + picoos_int32 len2, n2; + type = picoos_atoi(tok->markupParams[0].paramVal); + info1 = picoos_atoi(tok->markupParams[1].paramVal); + info2 = picoos_atoi(tok->markupParams[2].paramVal); + n = 0; n2 = 0; + len2 = (picoos_int32)picoos_strlen(tok->markupParams[3].paramVal); + while (nmarkupParams[3].paramVal[n] != 0) && (tok->markupParams[3].paramVal[n] <= 32)) { + n++; + } + tok->markupParams[3].paramVal[n2] = tok->markupParams[3].paramVal[n]; + n++; + n2++; + } + if (is_valid_itemtype(type)) { + done = TRUE; + len = 0; + pos = 0; + picoos_get_sep_part_str(tok->markupParams[3].paramVal, picoos_strlen(tok->markupParams[3].paramVal), + &pos, ',', part, 10, &done1); + while (done && done1) { + n = picoos_atoi(part); + if ((n>=0) && (n<256) && (len<256)) { + data[len++] = n; + } + else { + done = FALSE; + } + picoos_get_sep_part_str(tok->markupParams[3].paramVal, picoos_strlen(tok->markupParams[3].paramVal), + &pos, ',', part, 10, &done1); + } + if (done) { + tok_putItem2(this, tok, type, info1, info2, len, data); + } + } + else { + done = FALSE; + } + } else if (!isStartTag && tok_strEqual(tok->markupParams[0].paramId,(picoos_uchar*)"")) { + done = TRUE; + } + break; + default: + break; + } + if (!done) { + tok->markupTagErr = MEInterprete; + } + if (isStartTag) { + tok->markupLevel[mId]++; + } else if ((tok->markupLevel[mId] > 0)) { + tok->markupLevel[mId]--; + } +} + + +static picoos_bool tok_attrChar (picoos_uchar ch, picoos_bool first) +{ + return ((((ch >= (picoos_uchar)'A') && (ch <= (picoos_uchar)'Z')) || + ((ch >= (picoos_uchar)'a') && (ch <= (picoos_uchar)'z'))) || + ( !(first) && ((ch >= (picoos_uchar)'0') && (ch <= (picoos_uchar)'9')))); +} + + + +static picoos_bool tok_idChar (picoos_uchar ch, picoos_bool first) +{ + return tok_attrChar(ch, first) || ( !(first) && (ch == (picoos_uchar)':')); +} + + +static void tok_setIsFileAttr (picoos_uchar name[], picoos_bool * isFile) +{ + (*isFile) = tok_strEqual(name, KWFile); +} + +/* *****************************************************************************/ + +static void tok_putToSimpleToken (picodata_ProcessingUnit this, tok_subobj_t * tok, picoos_uchar str[], pico_tokenType type, pico_tokenSubType subtype) +{ + int i, len; + + if (str[0] != 0) { + len = picoos_strlen((picoos_char*)str); + for (i = 0; i < len; i++) { + if (tok->tokenPos >= IN_BUF_SIZE) { + picoos_emRaiseWarning(this->common->em, PICO_ERR_INTERNAL_LIMIT, (picoos_char*)"", (picoos_char*)"simple token too long; forced treatment"); + tok_treatSimpleToken(this, tok); + } + tok->tokenStr[tok->tokenPos] = str[i]; + tok->tokenPos++; + } + } + tok->tokenType = type; + tok->tokenSubType = subtype; +} + + +static void tok_putToMarkup (picodata_ProcessingUnit this, tok_subobj_t * tok, picoos_uchar str[]) +{ + picoos_int32 i, len; + picoos_uint8 ok; + + tok->markupTagErr = MENone; + len = picoos_strlen((picoos_char*)str); + for (i = 0; i< len; i++) { + if (tok->markupPos >= (MARKUP_STRING_BUF_SIZE - 1)) { + if ((tok->markupPos == (MARKUP_STRING_BUF_SIZE - 1)) && (tok_markupTagId(tok->markupTagName) != MIDummyEnd)) { + picoos_emRaiseWarning(this->common->em, PICO_ERR_INTERNAL_LIMIT ,(picoos_char*)"", (picoos_char*)"markup tag too long"); + } + tok->markupState = MSErrorTooLong; + } else if ((str[i] == (picoos_uchar)' ') && ((tok->markupState == MSExpectingmarkupTagName) || (tok->markupState == MSGotmarkupTagName) || (tok->markupState == MSGotAttrName) || (tok->markupState == MSGotEqual) || (tok->markupState == MSGotAttrValue))) { + } else if ((str[i] == (picoos_uchar)'>') && ((tok->markupState == MSGotmarkupTagName) || (tok->markupState == MSInmarkupTagName) || (tok->markupState == MSGotAttrValue))) { + tok->markupState = MSGotEnd; + } else if ((str[i] == (picoos_uchar)'/') && ((tok->markupState == MSGotmarkupTagName) || (tok->markupState == MSInmarkupTagName) || (tok->markupState == MSGotAttrValue))) { + if (tok->markupTagType == MTEnd) { + tok->markupTagErr = MEUnexpectedChar; + tok->markupState = MSError; + } else { + tok->markupTagType = MTEmpty; + tok->markupState = MSGotEndSlash; + } + } else { + switch (tok->markupState) { + case MSNotInMarkup: + if (str[i] == (picoos_uchar)'<') { + tok_clearMarkupParams(tok->markupParams); + tok->nrMarkupParams = 0; + tok->strPos = 0; + tok->markupTagType = MTStart; + tok->markupState = MSGotStart; + } else { + tok->markupTagErr = MEMissingStart; + tok->markupState = MSError; + } + break; + case MSGotStart: + if (str[i] == (picoos_uchar)'/') { + tok->markupTagType = MTEnd; + tok->markupState = MSExpectingmarkupTagName; + } else if (str[i] == (picoos_uchar)' ') { + tok->markupState = MSExpectingmarkupTagName; + } else if (tok_idChar(str[i],TRUE)) { + tok->markupTagType = MTStart; + tok->markupTagName[tok->strPos] = str[i]; + tok->strPos++; + tok->markupTagName[tok->strPos] = 0; + tok->markupState = MSInmarkupTagName; + } else { + tok->markupTagErr = MEUnexpectedChar; + tok->markupState = MSError; + } + break; + case MSInmarkupTagName: case MSExpectingmarkupTagName: + if (tok_idChar(str[i],tok->markupState == MSExpectingmarkupTagName)) { + tok->markupTagName[tok->strPos] = str[i]; + tok->strPos++; + tok->markupTagName[(tok->strPos)] = 0; + tok->markupState = MSInmarkupTagName; + } else if ((tok->markupState == MSInmarkupTagName) && (str[i] == (picoos_uchar)' ')) { + tok->markupState = MSGotmarkupTagName; + picobase_lowercase_utf8_str(tok->markupTagName, (picoos_char*)tok->markupTagName, IN_BUF_SIZE, &ok); + tok->strPos = 0; + } else { + tok->markupTagErr = MEIdent; + tok->markupState = MSError; + } + break; + case MSGotmarkupTagName: case MSGotAttrValue: + if (tok_attrChar(str[i], TRUE)) { + if (tok->markupTagType == MTEnd) { + tok->markupTagErr = MEUnexpectedChar; + tok->markupState = MSError; + } else { + if (tok->nrMarkupParams < MAX_NR_MARKUP_PARAMS) { + tok->markupParams[tok->nrMarkupParams].paramId[tok->strPos] = str[i]; + tok->strPos++; + tok->markupParams[tok->nrMarkupParams].paramId[tok->strPos] = 0; + } else { + picoos_emRaiseWarning(this->common->em, PICO_ERR_INTERNAL_LIMIT ,(picoos_char*)"", (picoos_char*)"too many attributes in markup; ignoring"); + } + tok->markupState = MSInAttrName; + } + } else { + tok->markupTagErr = MEUnexpectedChar; + tok->markupState = MSError; + } + break; + case MSInAttrName: + if (tok_attrChar(str[i], FALSE)) { + if (tok->nrMarkupParams < MAX_NR_MARKUP_PARAMS) { + tok->markupParams[tok->nrMarkupParams].paramId[tok->strPos] = str[i]; + tok->strPos++; + tok->markupParams[tok->nrMarkupParams].paramId[tok->strPos] = 0; + } + tok->markupState = MSInAttrName; + } else if (str[i] == (picoos_uchar)' ') { + picobase_lowercase_utf8_str(tok->markupParams[tok->nrMarkupParams].paramId, (picoos_char*)tok->markupParams[tok->nrMarkupParams].paramId, IN_BUF_SIZE, &ok); + tok_setIsFileAttr(tok->markupParams[tok->nrMarkupParams].paramId, & tok->isFileAttr); + tok->markupState = MSGotAttrName; + } else if (str[i] == (picoos_uchar)'=') { + picobase_lowercase_utf8_str(tok->markupParams[tok->nrMarkupParams].paramId, (picoos_char*)tok->markupParams[tok->nrMarkupParams].paramId, IN_BUF_SIZE, &ok); + tok_setIsFileAttr(tok->markupParams[tok->nrMarkupParams].paramId, & tok->isFileAttr); + tok->markupState = MSGotEqual; + } else { + tok->markupTagErr = MEMissingEqual; + tok->markupState = MSError; + } + break; + case MSGotAttrName: + if (str[i] == (picoos_uchar)'=') { + tok->markupState = MSGotEqual; + } else { + tok->markupTagErr = MEMissingEqual; + tok->markupState = MSError; + } + break; + case MSGotEqual: + if ((str[i] == (picoos_uchar)'"') || (str[i] == (picoos_uchar)'\'')) { + tok->strDelim = str[i]; + tok->strPos = 0; + tok->markupState = MSInAttrValue; + } else { + tok->markupTagErr = MEMissingQuote; + tok->markupState = MSError; + } + break; + case MSInAttrValue: + if (!(tok->isFileAttr) && (str[i] == (picoos_uchar)'\\')) { + tok->markupState = MSInAttrValueEscaped; + } else if (str[i] == tok->strDelim) { + if (tok->nrMarkupParams < MAX_NR_MARKUP_PARAMS) { + tok->nrMarkupParams++; + } + tok->strPos = 0; + tok->markupState = MSGotAttrValue; + } else { + if (tok->nrMarkupParams < MAX_NR_MARKUP_PARAMS) { + tok->markupParams[tok->nrMarkupParams].paramVal[tok->strPos] = str[i]; + tok->strPos++; + tok->markupParams[tok->nrMarkupParams].paramVal[tok->strPos] = 0; + } + tok->markupState = MSInAttrValue; + } + break; + case MSInAttrValueEscaped: + if (tok->nrMarkupParams < MAX_NR_MARKUP_PARAMS) { + tok->markupParams[tok->nrMarkupParams].paramVal[tok->strPos] = str[i]; + tok->strPos++; + tok->markupParams[tok->nrMarkupParams].paramVal[tok->strPos] = 0; + } + tok->markupState = MSInAttrValue; + break; + case MSGotEndSlash: + if (str[i] == (picoos_uchar)'>') { + tok->markupState = MSGotEnd; + } else { + tok->markupTagErr = MEUnexpectedChar; + tok->markupState = MSError; + } + break; + default: + tok->markupTagErr = MEUnexpectedChar; + tok->markupState = MSError; + break; + } + } + if (tok->markupTagErr == MENone) { + tok->markupStr[tok->markupPos] = str[i]; + tok->markupPos++; + } /* else restart parsing at current char */ + tok->markupStr[tok->markupPos] = 0; + } + /* + PICODBG_DEBUG(("putToMarkup %s", tok->markupStr)); + */ +} + +/* *****************************************************************************/ + +static void tok_treatMarkupAsSimpleToken (picodata_ProcessingUnit this, tok_subobj_t * tok) +{ + picoos_int32 i; + + tok->utfpos = 0; + tok->utflen = 0; + tok->markupState = MSNotInMarkup; + for (i = 0; i < tok->markupPos; i++) { + tok_treatChar(this, tok, tok->markupStr[i], FALSE); + } + tok->markupPos = 0; + tok->strPos = 0; +} + + +static void tok_treatMarkup (picodata_ProcessingUnit this, tok_subobj_t * tok) +{ + MarkupId mId; + + if (tok_markupTagId(tok->markupTagName) != MIDummyEnd) { + if (tok->markupTagErr == MENone) { + tok->markupState = MSNotInMarkup; + if ((tok->tokenType != PICODATA_ITEMINFO1_TOKTYPE_SPACE) && (tok->tokenType != PICODATA_ITEMINFO1_TOKTYPE_UNDEFINED)) { + tok_treatSimpleToken(this, tok); + } + tok_putToSimpleToken(this, tok, (picoos_uchar*)" ", PICODATA_ITEMINFO1_TOKTYPE_SPACE, -1); + mId = tok_markupTagId(tok->markupTagName); + if ((tok->markupTagType == MTStart) || (tok->markupTagType == MTEmpty)) { + tok_interpretMarkup(this, tok, TRUE, mId); + } + if (((tok->markupTagType == MTEnd) || (tok->markupTagType == MTEmpty))) { + tok_clearMarkupParams(tok->markupParams); + tok->nrMarkupParams = 0; + tok_interpretMarkup(this, tok, FALSE,mId); + } + } + if (tok->markupTagErr != MENone) { + if (!tok->aborted) { + picoos_emRaiseWarning(this->common->em, PICO_ERR_INVALID_MARKUP_TAG, (picoos_char*)"", (picoos_char*)"syntax error in markup token '%s'",tok->markupStr); + } + tok_treatMarkupAsSimpleToken(this, tok); + } + } else { + tok_treatMarkupAsSimpleToken(this, tok); + } + tok->markupState = MSNotInMarkup; + tok->markupPos = 0; + tok->strPos = 0; +} + + + +static void tok_treatChar (picodata_ProcessingUnit this, tok_subobj_t * tok, picoos_uchar ch, picoos_bool markupHandling) +{ + picoos_int32 i, id; + picoos_uint8 uval8; + pico_tokenType type = PICODATA_ITEMINFO1_TOKTYPE_UNDEFINED; + pico_tokenSubType subtype = -1; + picoos_bool dummy; + utf8char0c utf2; + picoos_int32 utf2pos; + + if (ch == NULLC) { + tok_treatSimpleToken(this, tok); + tok_putItem(this, tok, PICODATA_ITEM_CMD, PICODATA_ITEMINFO1_CMD_FLUSH, PICODATA_ITEMINFO2_NA, 0, (picoos_uchar*)""); + } + else { + switch (tok_putToUtf(tok, ch)) { + case UTF_CHAR_MALFORMED: + tok->utfpos = 0; + tok->utflen = 0; + break; + case UTF_CHAR_INCOMPLETE: + break; + case UTF_CHAR_COMPLETE: + markupHandling = (markupHandling && (tok->markupHandlingMode == MARKUP_HANDLING_ENABLED)); + id = picoktab_graphOffset(tok->graphTab, tok->utf); + if (id > 0) { + if (picoktab_getIntPropTokenType(tok->graphTab, id, &uval8)) { + type = (pico_tokenType)uval8; + if (type == PICODATA_ITEMINFO1_TOKTYPE_LETTERV) { + type = PICODATA_ITEMINFO1_TOKTYPE_LETTER; + } + } + dummy = picoktab_getIntPropTokenSubType(tok->graphTab, id, &subtype); + } else if (tok->utf[tok->utfpos-1] <= (picoos_uchar)' ') { + type = PICODATA_ITEMINFO1_TOKTYPE_SPACE; + subtype = -1; + } else { + type = PICODATA_ITEMINFO1_TOKTYPE_UNDEFINED; + subtype = -1; + } + if ((tok->utf[tok->utfpos-1] > (picoos_uchar)' ')) { + tok->nrEOL = 0; + } else if (tok->utf[tok->utfpos-1] == EOL) { + tok->nrEOL++; + } + if (markupHandling && (tok->markupState != MSNotInMarkup)) { + tok_putToMarkup(this, tok, tok->utf); + if (tok->markupState >= MSError) { + picoos_strlcpy(utf2, tok->utf, 5); + utf2pos = tok->utfpos; + /* treat string up to (but not including) current char as simple + token and restart markup tag parsing with current char */ + tok_treatMarkupAsSimpleToken(this, tok); + for (i = 0; i < utf2pos; i++) { + tok_treatChar(this, tok, utf2[i], markupHandling); + } + } else if (tok->markupState == MSGotEnd) { + tok_treatMarkup(this, tok); + } + } else if ((markupHandling && (tok->utf[tok->utfpos-1] == (picoos_uchar)'<'))) { + tok_putToMarkup(this, tok, tok->utf); + } else if (type != PICODATA_ITEMINFO1_TOKTYPE_UNDEFINED) { + if ((type != tok->tokenType) || (type == PICODATA_ITEMINFO1_TOKTYPE_CHAR) || (subtype != tok->tokenSubType)) { + tok_treatSimpleToken(this, tok); + } else if ((tok->utf[tok->utfpos-1] == EOL) && (tok->nrEOL == 2)) { + tok_treatSimpleToken(this, tok); + tok_putToSimpleToken(this, tok, (picoos_uchar*)".", PICODATA_ITEMINFO1_TOKTYPE_CHAR, -1); + tok_treatSimpleToken(this, tok); + } + tok_putToSimpleToken(this, tok, tok->utf, type, subtype); + } else { + tok_treatSimpleToken(this, tok); + } + tok->utfpos = 0; + tok->utflen = 0; + break; + } + } +} + + +static void tok_treatSimpleToken (picodata_ProcessingUnit this, tok_subobj_t * tok) +{ + if (tok->tokenPos < IN_BUF_SIZE) { + tok->tokenStr[tok->tokenPos] = 0; + } + if (tok->markupState != MSNotInMarkup) { + if (!(tok->aborted) && (tok->markupState >= MSGotmarkupTagName) && (tok_markupTagId(tok->markupTagName) != MIDummyEnd)) { + picoos_emRaiseWarning(this->common->em, PICO_ERR_INVALID_MARKUP_TAG, (picoos_char*)"", (picoos_char*)"unfinished markup tag '%s'",tok->markupStr); + } + tok_treatMarkupAsSimpleToken(this, tok); + tok_treatSimpleToken(this, tok); + } else if ((tok->tokenPos > 0) && ((tok->ignLevel <= 0) || (tok->tokenType == PICODATA_ITEMINFO1_TOKTYPE_SPACE))) { + tok_putItem(this, tok, PICODATA_ITEM_TOKEN, tok->tokenType, (picoos_uint8)tok->tokenSubType, 0, tok->tokenStr); + } + tok->tokenPos = 0; + tok->tokenType = PICODATA_ITEMINFO1_TOKTYPE_UNDEFINED; + tok->tokenSubType = -1; +} + +/* *****************************************************************************/ + +static pico_status_t tokReset(register picodata_ProcessingUnit this, picoos_int32 resetMode) +{ + tok_subobj_t * tok; + MarkupId mId; + + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + tok = (tok_subobj_t *) this->subObj; + + tok->ignLevel = 0; + + tok->utfpos = 0; + tok->utflen = 0; + + tok_clearMarkupParams(tok->markupParams); + tok->nrMarkupParams = 0; + tok->markupState = MSNotInMarkup; + tok->markupPos = 0; + for (mId = MIDummyStart; mId <= MIDummyEnd; mId++) { + tok->markupLevel[mId] = 0; + } + tok->markupTagName[0] = 0; + tok->markupTagType = MTNone; + tok->markupTagErr = MENone; + + tok->strPos = 0; + tok->strDelim = 0; + tok->isFileAttr = FALSE; + + tok->tokenType = PICODATA_ITEMINFO1_TOKTYPE_UNDEFINED; + tok->tokenSubType = -1; + tok->tokenPos = 0; + + tok->nrEOL = 0; + + + tok->markupHandlingMode = TRUE; + tok->aborted = FALSE; + + tok->start = TRUE; + + tok->outReadPos = 0; + tok->outWritePos = 0; + + tok->saveFile[0] = 0; + + + tok->graphTab = picoktab_getGraphs(this->voice->kbArray[PICOKNOW_KBID_TAB_GRAPHS]); + + tok->xsampa_parser = picokfst_getFST(this->voice->kbArray[PICOKNOW_KBID_FST_XSAMPA_PARSE]); + PICODBG_TRACE(("got xsampa_parser @ %i",tok->xsampa_parser)); + + tok->svoxpa_parser = picokfst_getFST(this->voice->kbArray[PICOKNOW_KBID_FST_SVOXPA_PARSE]); + PICODBG_TRACE(("got svoxpa_parser @ %i",tok->svoxpa_parser)); + + tok->xsampa2svoxpa_mapper = picokfst_getFST(this->voice->kbArray[PICOKNOW_KBID_FST_XSAMPA2SVOXPA]); + PICODBG_TRACE(("got xsampa2svoxpa_mapper @ %i",tok->xsampa2svoxpa_mapper)); + + + + return PICO_OK; +} + +static pico_status_t tokInitialize(register picodata_ProcessingUnit this, picoos_int32 resetMode) +{ +/* + + tok_subobj_t * tok; + + if (NULL == this || NULL == this->subObj) { + return PICO_ERR_OTHER; + } + tok = (tok_subobj_t *) this->subObj; +*/ + return tokReset(this, resetMode); +} + + +static pico_status_t tokTerminate(register picodata_ProcessingUnit this) +{ + return PICO_OK; +} + +static picodata_step_result_t tokStep(register picodata_ProcessingUnit this, picoos_int16 mode, picoos_uint16 * numBytesOutput); + +static pico_status_t tokSubObjDeallocate(register picodata_ProcessingUnit this, + picoos_MemoryManager mm) +{ + + if (NULL != this) { + picoos_deallocate(this->common->mm, (void *) &this->subObj); + } + mm = mm; /* avoid warning "var not used in this function"*/ + return PICO_OK; +} + +picodata_ProcessingUnit picotok_newTokenizeUnit(picoos_MemoryManager mm, picoos_Common common, + picodata_CharBuffer cbIn, picodata_CharBuffer cbOut, + picorsrc_Voice voice) +{ + tok_subobj_t * tok; + picodata_ProcessingUnit this = picodata_newProcessingUnit(mm, common, cbIn, cbOut, voice); + if (this == NULL) { + return NULL; + } + this->initialize = tokInitialize; + PICODBG_DEBUG(("set this->step to tokStep")); + this->step = tokStep; + this->terminate = tokTerminate; + this->subDeallocate = tokSubObjDeallocate; + this->subObj = picoos_allocate(mm, sizeof(tok_subobj_t)); + if (this->subObj == NULL) { + picoos_deallocate(mm, (void *)&this); + return NULL; + } + tok = (tok_subobj_t *) this->subObj; + tok->transducer = picotrns_newSimpleTransducer(mm, common, 10*(PICOTRNS_MAX_NUM_POSSYM+2)); + if (NULL == tok->transducer) { + tokSubObjDeallocate(this,mm); + picoos_deallocate(mm, (void *)&this); + return NULL; + } + tokInitialize(this, PICO_RESET_FULL); + return this; +} + +/** + * fill up internal buffer, try to locate token, write token to output + */ +picodata_step_result_t tokStep(register picodata_ProcessingUnit this, + picoos_int16 mode, picoos_uint16 * numBytesOutput) +{ + register tok_subobj_t * tok; + + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + tok = (tok_subobj_t *) this->subObj; + + mode = mode; /* avoid warning "var not used in this function"*/ + + *numBytesOutput = 0; + while (1) { /* exit via return */ + picoos_int16 ch; + + if ((tok->outWritePos - tok->outReadPos) > 0) { + if (picodata_cbPutItem(this->cbOut, &tok->outBuf[tok->outReadPos], tok->outWritePos - tok->outReadPos, numBytesOutput) == PICO_OK) { + PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG], + (picoos_uint8 *)"tok:", &tok->outBuf[tok->outReadPos], tok->outWritePos - tok->outReadPos); + tok->outReadPos += *numBytesOutput; + if (tok->outWritePos == tok->outReadPos) { + tok->outWritePos = 0; + tok->outReadPos = 0; + } + } + else { + return PICODATA_PU_OUT_FULL; + } + + } + else if (PICO_EOF != (ch = picodata_cbGetCh(this->cbIn))) { + PICODBG_DEBUG(("read in %c", (picoos_char) ch)); + tok_treatChar(this, tok, (picoos_uchar) ch, /*markupHandling*/TRUE); + } + else { + return PICODATA_PU_IDLE; + } + } +} + +#ifdef __cplusplus +} +#endif + +/* end */ diff --git a/pico/lib/picotok.h b/pico/lib/picotok.h new file mode 100644 index 0000000..b602408 --- /dev/null +++ b/pico/lib/picotok.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picotok.h + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + + +/** @addtogroup picotok +itemtype, iteminfo1, iteminfo2, content -> TYPE(INFO1,INFO2)content +in the following + +input +===== + +- UTF8 text + +limitations: currently only german umlauts in addition to ASCII + + +minimal input size (before processing starts) +================== + +processing (ie. tokenization) starts when +- 'PICO_EOF' char received (which happens whenever the cbIn buffer is empty) +- tok-internal buffer is full + + +items output +============ + +processing the character stream can result in one of the +following items: +-> WORDGRAPH(NA,NA)graph <- mapped to lower case; incl. 1-2 digit nrs (0-99) +-> OTHER(NA,NA)string <- skip or spell +-> PUNC(PUNCtype,PUNCsubtype) +-> CMD(CMDtype,CMDsubtype)args + +with +- PUNCtype %d + PICODATA_ITEMINFO1_PUNC_SENTEND + PICODATA_ITEMINFO1_PUNC_PHRASEEND +- PUNCsubtype %d + PICODATA_ITEMINFO2_PUNC_SENT_T + PICODATA_ITEMINFO2_PUNC_SENT_Q + PICODATA_ITEMINFO2_PUNC_SENT_E + PICODATA_ITEMINFO2_PUNC_PHRASE + (used later: PICODATA_ITEMINFO2_PUNC_PHRASE_FORCED) +- CMDtype %d + PICODATA_ITEMINFO1_CMD_FLUSH (no args) + ? PICODATA_ITEMINFO1_CMD_PLAY ? (not yet) +- CMDsubtype %d + PICODATA_ITEMINFO2_NA + ? PICODATA_ITEMINFO2_CMD_PLAY_G2P ? (not yet) +- graph, len>0, utf8 graphemes, %s +- string, len>0, can be any string with printable ascii characters, %s + + +other limitations +================= + +- item size: header plus len=256 (valid for Pico in general) + */ + + +#ifndef PICOTOK_H_ +#define PICOTOK_H_ + +#include "picoos.h" +#include "picodata.h" +#include "picorsrc.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + + +picodata_ProcessingUnit picotok_newTokenizeUnit( + picoos_MemoryManager mm, + picoos_Common common, + picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, + picorsrc_Voice voice); + +#define PICOTOK_OUTBUF_SIZE 256 + +#ifdef __cplusplus +} +#endif + + +#endif /*PICOTOK_H_*/ diff --git a/pico/lib/picotrns.c b/pico/lib/picotrns.c new file mode 100644 index 0000000..2d16340 --- /dev/null +++ b/pico/lib/picotrns.c @@ -0,0 +1,745 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picotrns.c + * + * fst processing + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include "picoos.h" +#include "picodbg.h" +/* #include "picodata.h" */ +/* #include "picoknow.h" */ +#include "picoktab.h" +#include "picokfst.h" +#include "picotrns.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + + +picoos_uint8 picotrns_unplane(picoos_int16 symIn, picoos_uint8 * plane) { + if (symIn < 0) { + (*plane) = 0; + return (picoos_uint8) symIn; + } else { + (*plane) = symIn >> 8; + return (picoos_uint8) (symIn & 0xFF); + } +} + +#if defined(PICO_DEBUG) + +void PICOTRNS_PRINTSYM1(picoknow_KnowledgeBase kbdbg, picoos_int16 insym, picoos_uint8 phonemic) +{ +#include "picokdbg.h" + picoos_int16 sym; + picoos_uint8 plane; + picokdbg_Dbg dbg = (NULL == kbdbg) ? NULL : picokdbg_getDbg(kbdbg); + sym = picotrns_unplane(insym, &plane); + switch (plane) { + case PICOKFST_PLANE_PHONEMES: /* phones */ + if ((NULL == dbg) || !phonemic) { + PICODBG_INFO_MSG((" %c", sym)); + } else { + PICODBG_INFO_MSG((" %s", picokdbg_getPhoneSym(dbg, (picoos_uint8) sym))); + } + break; + case PICOKFST_PLANE_ACCENTS: /* accents */ + PICODBG_INFO_MSG((" {A%c}", sym)); + break; + case PICOKFST_PLANE_XSAMPA: /* xsampa symbols */ + PICODBG_INFO_MSG((" {XS:(%i)}", sym)); + break; + case PICOKFST_PLANE_POS: /* part of speech */ + PICODBG_INFO_MSG((" {P:%d}", sym)); + break; + case PICOKFST_PLANE_PB_STRENGTHS: /* phrases */ + if (sym == 48) { + PICODBG_INFO_MSG((" {WB}", sym)); + } else if (sym == 115) { + PICODBG_INFO_MSG((" {P0}", sym)); + } else { + PICODBG_INFO_MSG((" {P%c}", sym)); + } + break; + case PICOKFST_PLANE_INTERN: /* intern */ + PICODBG_INFO_MSG((" [%c]", sym)); + break; + } +} + +void PICOTRNS_PRINTSYM(picoknow_KnowledgeBase kbdbg, picoos_int16 insym) +{ + PICOTRNS_PRINTSYM1(kbdbg,insym,1); +} + +void PICOTRNS_PRINTSYMSEQ1(picoknow_KnowledgeBase kbdbg, const picotrns_possym_t seq[], const picoos_uint16 seqLen, + picoos_uint8 phonemic) { + picoos_uint16 i; + for (i=0; i= maxOutSeqLen) { + return PICO_EXC_BUF_OVERFLOW; + } + /* let j skip consonant cluster */ + accent = 0; + accentpos = 0; + while ((j < inSeqLen) && !picoktab_isSyllCarrier(phones,(picoos_uint8)inSeq[j].sym)) { + if ((inSeq[j].sym == picoktab_getPrimstressID(phones)) + || (inSeq[j].sym == picoktab_getPrimstressID(phones))) { + PICODBG_TRACE(("j skipping stress symbol inSeq[%i].sym = %c", j, inSeq[j].sym)); + accent = inSeq[j].sym; + accentpos = j; + } else { + PICODBG_TRACE(("j skipping consonant inSeq[%i].sym = %c", j, inSeq[j].sym)); + } + j++; + } + if (j < inSeqLen) { /* j is at the start of a new vowel */ + /* copy consonant cluster (moving i) to output, insert syll separator if between vowels */ + while (i < j-1) { + if ((accent > 0) && (i == accentpos)) { + PICODBG_TRACE(("skipping inSeq[%i].sym = %c (stress)", i, inSeq[i].sym)); + i++; + } else { + PICODBG_TRACE(("copying inSeq[%i].sym = %c (consonant) into output buffer", i, inSeq[i].sym)); + outSeq[out++] = inSeq[i++]; + } + } + if (vowelFound) { /* we're between vowels */ + PICODBG_TRACE(("inserting syllable separator into output buffer")); + insertSym(outSeq,out++,picoktab_getSyllboundID(phones)); + if (accent > 0) { + insertSym(outSeq,out++,accent); + } + numInserted++; + } + if ((accent > 0) && (i == accentpos)) { + PICODBG_TRACE(("skipping inSeq[%i].sym = %c (stress)", i, inSeq[i].sym)); + i++; + } else { + PICODBG_TRACE(("copying inSeq[%i].sym = %c (consonant) into output buffer", i, inSeq[i].sym)); + outSeq[out++] = inSeq[i++]; + } + vowelFound = TRUE; + /* now copy vowel cluster */ + while ((i < inSeqLen) && picoktab_isSyllCarrier(phones,(picoos_uint8)inSeq[i].sym)) { + PICODBG_TRACE(("copying inSeq[%i].sym = %c (vowel) into output buffer", i, inSeq[i].sym)); + outSeq[out++] = inSeq[i++]; + } + j = i; + } else { /* j is at end of word or end of input */ + while (i < j) { + PICODBG_TRACE(("copying inSeq[%i].sym = %c (consonant or stress) into output buffer", i, inSeq[i].sym)); + outSeq[out++] = inSeq[i++]; + } + } + *outSeqLen = out; + } + PICODBG_ASSERT((out == inSeqLen + numInserted)); + + return PICO_OK; +} + + +/* ******** +CT+: full transduction procedure **********/ + + +/* Gets next acceptable alternative for output symbol '*outSym' at current recursion position + starting from previous alternative in 'altDesc'; possibly uses input symbol + given by 'inSeq'/'inSeq'; returns whether alterative was found in '*found'; + if '*found', the other output values ('*outRefPos', '*endFSTstate', '*nextInPos'*) + return the characteristics for next recursion step; + if '*found' is false, the output values are undefined. */ + +static void GetNextAlternative (picokfst_FST fst, picotrns_AltDesc altDesc, + const picotrns_possym_t inSeq[], picoos_uint16 inSeqLen, + picokfst_symid_t * outSym, picoos_int32 * outRefPos, + picokfst_state_t * endFSTState, picoos_int32 * nextInPos, picoos_bool * found) +{ + + picoos_bool inSymFound; + picoos_bool pairFound; + picokfst_class_t pairClass; + picoos_bool inEpsTransFound; + picokfst_symid_t inSym; + + (*found) = 0; + do { + switch (altDesc->altState) { + case 0: /* before pair search */ + if (altDesc->inPos < inSeqLen) { + inSym = inSeq[altDesc->inPos].sym; + if (inSym == PICOKFST_SYMID_EPS) { + /* very special case: input epsilon simply produces eps in output + without fst state change */ + (*found) = 1; + (*outSym) = PICOKFST_SYMID_EPS; + (*outRefPos) = inSeq[altDesc->inPos].pos; + (*endFSTState) = altDesc->startFSTState; + (*nextInPos) = altDesc->inPos + 1; + altDesc->altState = 2; + } else { + /* start search for alternatives using input symbol */ + picokfst_kfstStartPairSearch(fst,inSeq[altDesc->inPos].sym,& inSymFound,& altDesc->searchState); + if (!inSymFound) { + altDesc->altState = 2; + PICODBG_INFO_CTX(); + PICODBG_INFO_MSG((" didnt find symbol ")); + PICOTRNS_PRINTSYM(NULL, inSeq[altDesc->inPos].sym); + PICODBG_INFO_MSG(("\n")); + + } else { + altDesc->altState = 1; + } + } + } else { + altDesc->altState = 2; + } + break; + case 1: /* within pair search */ + picokfst_kfstGetNextPair(fst,& altDesc->searchState,& pairFound,& (*outSym),& pairClass); + if (pairFound) { + picokfst_kfstGetTrans(fst,altDesc->startFSTState,pairClass,& (*endFSTState)); + if ((*endFSTState) > 0) { + (*found) = 1; + (*outRefPos) = inSeq[altDesc->inPos].pos; + (*nextInPos) = altDesc->inPos + 1; + } + } else { + /* no more pair found */ + altDesc->altState = 2; + } + break; + case 2: /* before inEps trans search */ + picokfst_kfstStartInEpsTransSearch(fst,altDesc->startFSTState,& inEpsTransFound,& altDesc->searchState); + if (inEpsTransFound) { + altDesc->altState = 3; + } else { + altDesc->altState = 4; + } + break; + case 3: /* within inEps trans search */ + picokfst_kfstGetNextInEpsTrans(fst,& altDesc->searchState,& inEpsTransFound,& (*outSym),& (*endFSTState)); + if (inEpsTransFound) { + (*found) = 1; + (*outRefPos) = PICOTRNS_POS_INSERT; + (*nextInPos) = altDesc->inPos; + } else { + altDesc->altState = 4; + } + break; + case 4: /* no more alternatives */ + break; + } + } while (! ((*found) || (altDesc->altState == 4)) ); /* i.e., until (*found) || (altState == 4) */ +} + + + +/* Transfers current alternatives path stored in 'altDesc' with current path length 'pathLen' + into 'outSeq'/'outSeqLen'. The number of solutions is incremented. */ + +static void NoteSolution (picoos_uint32 * nrSol, picotrns_printSolutionFct printSolution, + picotrns_altDesc_t altDesc[], picoos_uint16 pathLen, + picotrns_possym_t outSeq[], picoos_uint16 * outSeqLen, picoos_uint16 maxOutSeqLen) +{ + register picotrns_AltDesc ap; + picoos_uint32 i; + + (*nrSol)++; + (*outSeqLen) = 0; + for (i = 0; i < pathLen; i++) { + if (i < maxOutSeqLen) { + ap = &altDesc[i]; + outSeq[i].sym = ap->altOutSym; + outSeq[i].pos = ap->altOutRefPos; + (*outSeqLen)++; + } + } + if (pathLen > maxOutSeqLen) { + PICODBG_WARN(("**** output symbol array too small to hold full solution\n")); + } + if (printSolution != NULL) { + printSolution(outSeq,(*outSeqLen)); + } +} + + + +/* * + general scheme to get all solutions ("position" refers to abstract backtracking recursion depth, + which in the current solution is equal to the output symbol position): + + "set position to first position"; + "initialize alternatives in first position"; + REPEAT + IF "current state in current position is a solution" THEN + "note solution"; + END; + "get first or next acceptable alternative in current position"; + IF "acceptable alternative found" THEN + "note alternative"; + "go to next position"; + "initialize alternatives in that position"; + ELSE + "step back to previous position"; + END; + UNTIL "current position is before first position" +***/ + + +/* Initializes transduction state for further use in repeated application + of 'TransductionStep'. */ + +static void StartTransduction (struct picotrns_transductionState * transductionState) +{ + (*transductionState).phase = 0; +} + + + +/* Performs one step in the transduction of 'inSeqLen' input symbols with corresponding + reference positions in 'inSeq'. '*transductionState' must have been + initialized by 'StartTransduction'. Repeat calls to this procedure until '*finished' returns true. + The output is returned in 'outSeqLen' symbols and reference positions in 'outSeq'. + The output reference positions refer to the corresponding input reference positions. + Inserted output symbols receive the reference position -1. If several solutions are possible, + only the last found solution is returned. + 'altDesc' is a temporary workspace which should be at least one cell longer than 'outSeq'. + 'firstSolOnly' determines whether only the first solution should be found or if + the search should go on to find all solutions (mainly for testing purposes). + + NOTE: current version written for use in single repetitive steps; + could be simplified if full transduction can be done as an atomic operation */ + +static void TransductionStep (picokfst_FST fst, struct picotrns_transductionState * transductionState, + picotrns_altDesc_t altDesc[], picoos_uint16 maxAltDescLen, + picoos_bool firstSolOnly, picotrns_printSolutionFct printSolution, + const picotrns_possym_t inSeq[], picoos_uint16 inSeqLen, + picotrns_possym_t outSeq[], picoos_uint16 * outSeqLen, picoos_uint16 maxOutSeqLen, + picoos_bool * finished) +{ + register picotrns_AltDesc ap; + picoos_int32 i; + picokfst_state_t endFSTState; + picoos_int32 nextInPos; + picoos_bool found; + picokfst_symid_t outSym; + picoos_int32 outRefPos; + picoos_int32 tmpRecPos; + + (*finished) = 0; + tmpRecPos = (*transductionState).recPos; + switch ((*transductionState).phase) { + case 0: /* before initialization */ + (*transductionState).nrSol = 0; + + /* check for initial solution (empty strings are always accepted) */ + if (inSeqLen == 0) { + NoteSolution(& (*transductionState).nrSol,printSolution,altDesc,0,outSeq,outSeqLen,maxOutSeqLen); + } + + /* initialize first recursion position */ + tmpRecPos = 0; + ap = & altDesc[0]; + ap->startFSTState = 1; + ap->inPos = 0; + ap->altState = 0; + (*transductionState).phase = 1; + break; + + case 1: /* before regular recursion step */ + if ((tmpRecPos < 0) || (firstSolOnly && ((*transductionState).nrSol > 0))) { + /* end reached */ + (*transductionState).phase = 2; + } else { + /* not finished; do regular step */ + + /* get first or next acceptable alternative in current position */ + GetNextAlternative(fst,& altDesc[tmpRecPos],inSeq,inSeqLen,& outSym,& outRefPos,& endFSTState,& nextInPos,& found); + if (found) { + /* note alternative in current position */ + ap = & altDesc[tmpRecPos]; + ap->altOutSym = outSym; + ap->altOutRefPos = outRefPos; + + /* check for solution after found alternative */ + if ((nextInPos == inSeqLen) && picokfst_kfstIsAcceptingState(fst,endFSTState)) { + NoteSolution(& (*transductionState).nrSol,printSolution,altDesc,tmpRecPos+1, + outSeq,outSeqLen,maxOutSeqLen); + } + + /* go to next position if possible, start search for follower alternative symbols */ + if (tmpRecPos < maxAltDescLen-1) { + /* got to next position */ + tmpRecPos = tmpRecPos + 1; + + /* initialize alternatives in new position */ + ap = & altDesc[tmpRecPos]; + ap->startFSTState = endFSTState; + ap->inPos = nextInPos; + ap->altState = 0; + + } else { + /* do not go on due to limited path but still treat alternatives in current position */ + PICODBG_WARN(("--- transduction path too long; may fail to find solution\n")); + } + } else { /* no more acceptable alternative found in current position */ + /* backtrack to previous recursion */ + tmpRecPos = tmpRecPos - 1; + } + } + break; + + case 2: /* before finish */ + if ((*transductionState).nrSol == 0) { + PICODBG_WARN(("--- no transduction solution found, using input as output\n")); + i = 0; + while ((i < inSeqLen) && (i < maxOutSeqLen)) { + outSeq[i].sym = inSeq[i].sym; + outSeq[i].pos = inSeq[i].pos; + i++; + } + (*outSeqLen) = i; + } else if ((*transductionState).nrSol > 1) { + PICODBG_WARN(("--- more than one transducer solutions found\n")); + } + (*transductionState).phase = 3; + break; + + case 3: /* after finish */ + (*finished) = 1; + break; + } + (*transductionState).recPos = tmpRecPos; +} + + + +/* see description in header */ +pico_status_t picotrns_transduce (picokfst_FST fst, picoos_bool firstSolOnly, + picotrns_printSolutionFct printSolution, + const picotrns_possym_t inSeq[], picoos_uint16 inSeqLen, + picotrns_possym_t outSeq[], picoos_uint16 * outSeqLen, picoos_uint16 maxOutSeqLen, + picotrns_AltDesc altDescBuf, picoos_uint16 maxAltDescLen, + picoos_uint32 *nrSteps) +{ + struct picotrns_transductionState transductionState; + picoos_bool finished; + +#if defined(PICO_DEBUG) + { + picoos_uint16 i; + + PICODBG_INFO_CTX(); + PICODBG_INFO_MSG(("got input: ")); + for (i=0; ipossymBuf = transducer->possymBufA; + transducer->possymBufTmp = transducer->possymBufB; + transducer->possymReadPos = 0; + transducer->possymWritePos = 0; + return PICO_OK; +} +/** creates a SimpleTranducer with a working buffer of given size + * + * @param mm MemoryManager handle + * @param common Common handle + * @param maxAltDescLen maximal size for working buffer (in bytes) + * @return handle to new SimpleTransducer or NULL if error + */ +picotrns_SimpleTransducer picotrns_newSimpleTransducer(picoos_MemoryManager mm, + picoos_Common common, + picoos_uint16 maxAltDescLen) +{ + picotrns_SimpleTransducer this; + this = picoos_allocate(mm, sizeof(picotrns_simple_transducer_t)); + if (this == NULL) { + picoos_deallocate(mm, (void *)&this); + picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, NULL, NULL); + return NULL; + } + + /* allocate working buffer */ + this->altDescBuf = picotrns_allocate_alt_desc_buf(mm, maxAltDescLen, &this->maxAltDescLen); + if (this->altDescBuf == NULL) { + picoos_deallocate(mm, (void *)&this); + picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, NULL, NULL); + return NULL; + } + this->common = common; + picotrns_stInitialize(this); + return this; +} +/** disposes a SimpleTransducer + * + * @param this + * @param mm + * @return PICO_OK + */ +pico_status_t picotrns_disposeSimpleTransducer(picotrns_SimpleTransducer * this, + picoos_MemoryManager mm) +{ + if (NULL != (*this)) { + picotrns_deallocate_alt_desc_buf(mm,&(*this)->altDescBuf); + picoos_deallocate(mm, (void *) this); + (*this) = NULL; + } + return PICO_OK; +} + +/** transduces the contents previously inserted via @ref picotrns_newSimpleTransducer and @ref + * picotrns_disposeSimpleTransducer. + * + * @param this + * @param fst + * @return + */ +pico_status_t picotrns_stTransduce(picotrns_SimpleTransducer this, picokfst_FST fst) +{ + picoos_uint16 outSeqLen; + picoos_uint32 nrSteps; + pico_status_t status; + + status = picotrns_transduce(fst,TRUE,NULL, + this->possymBuf, this->possymWritePos, + this->possymBufTmp,&outSeqLen, PICOTRNS_MAX_NUM_POSSYM, + this->altDescBuf,this->maxAltDescLen,&nrSteps); + if (PICO_OK != status) { + return status; + } + return picotrns_eliminate_epsilons(this->possymBufTmp,outSeqLen,this->possymBuf,&this->possymWritePos,PICOTRNS_MAX_NUM_POSSYM); +} + +/** + * Add chars from NULLC-terminated string \c inStr, shifted to plane \c plane, to internal input buffer of + * \c transducer. + * + * @param this is an initialized picotrns_SimpleTransducer + * @param inStr NULLC-terminated byte sequence + * @param plane + * @return PICO_OK, if all bytes fit into buffer, or PICO_EXC_BUF_OVERFLOW otherwise + */ +pico_status_t picotrns_stAddWithPlane(picotrns_SimpleTransducer this, picoos_char * inStr, picoos_uint8 plane) +{ + while ((*inStr) && (this->possymWritePos < PICOTRNS_MAX_NUM_POSSYM)) { + this->possymBuf[this->possymWritePos].pos = PICOTRNS_POS_INSERT; + this->possymBuf[this->possymWritePos].sym = (plane << 8) + (*inStr); + PICODBG_DEBUG(("inserting pos/sym = %i/'%c' at pos %i", + this->possymBuf[this->possymWritePos].pos, + this->possymBuf[this->possymWritePos].sym, + this->possymWritePos)); + this->possymWritePos++; + inStr++; + } + if (!(*inStr)) { + return PICO_OK; + } else { + return PICO_EXC_BUF_OVERFLOW; + } +} + +pico_status_t picotrns_stGetSymSequence( + picotrns_SimpleTransducer this, + picoos_uint8 * outputSymIds, + picoos_uint32 maxOutputSymIds) +{ + picoos_uint8 plane; + picoos_uint32 outputCount = 0; + while ((this->possymReadPos < this->possymWritePos) && (outputCount < maxOutputSymIds)) { + *outputSymIds++ = picotrns_unplane(this->possymBuf[this->possymReadPos++].sym, &plane); + outputCount++; + } + *outputSymIds = NULLC; + if (outputCount <= maxOutputSymIds) { + return PICO_OK; + } else { + return PICO_EXC_BUF_OVERFLOW; + } +} + +#ifdef __cplusplus +} +#endif + +/* end picotrns.c */ diff --git a/pico/lib/picotrns.h b/pico/lib/picotrns.h new file mode 100644 index 0000000..f535ce0 --- /dev/null +++ b/pico/lib/picotrns.h @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picotrns.h + * + * fst processing + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +/** @addtogroup picotrns + * + * Conventions: + * + * - The input to the transducer is a list of pos/sym pairs, where pos are arbitrary position markers + * - All positions are allowed on input (in particular all those coming as an output of a previous transduction) + * - A phone sequence to be transduced has to begin with PICOKNOW_PHON_START_ID and end with PICOKNOW_PHON_TERM_ID + * These special symbols are kept in the transduction output (as first and last symbol) + * - Symbols inserted by the transduction process allways get their position marker pos=PICOTRNS_POS_INSERT + * - The order of positions on output must be the same as that on input, i.e. apart from inserted pairs, the + * output position sequence must be a sub-sequence of the input position sequence. + * - Inserted symbols are allways preceded by a positioned pos/sym pair, e.g. + * if the sequence pos1/sym1, pos2/sym2 should be tranduced to x/sym3, y/sym4, z/sym5, then x must be pos1 or pos2 + * and not PICOTRNS_POS_INSERT + * + * For lingware developers: Insertions are always interpreted "to the right" + * - E.g.: The original sequence is phon1 , command , phon2 + * - The input to the transducer is then pos1/phon1 , pos2/phon2 + * - The output is pos1/phon1' -1/phon_ins pos2/phon2' [assuming -1 is the special insertion pos] + * - Then the new sequence will be recomposed as phon1' , phon_ins , command , phon2' [note position of command!] + * - To overwrite this behaviour, rules must be formulated such that the transduction output is + * pos1/phon1' pos2/phon_ins -1/phon2' + */ +#ifndef PICOTRNS_H_ +#define PICOTRNS_H_ + +#include "picoos.h" +#include "picokfst.h" +#include "picoktab.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +#define PICOTRNS_MAX_NUM_POSSYM 255 + +#define PICOTRNS_POS_INSERT (picoos_int16) -1 /* position returned by transducer to mark symbols inserted by the transducer */ +#define PICOTRNS_POS_INVALID (picoos_int16) -2 /* value to mark an invalid (e.g. uninitiated) position */ +#define PICOTRNS_POS_IGNORE (picoos_int16) -3 /* value to mark a pos/sym pair to be ignored (e.g. start/term symbols only used by the transducer) */ + + +typedef struct picotrns_possym { + picoos_int16 pos; + picoos_int16 sym; +} picotrns_possym_t; + +picoos_uint8 picotrns_unplane(picoos_int16 symIn, picoos_uint8 * plane); + + +#if defined(PICO_DEBUG) + +void PICOTRNS_PRINTSYM(picoknow_KnowledgeBase kbdbg, picoos_int16 insym); + +void PICOTRNS_PRINTSYMSEQ(picoknow_KnowledgeBase kbdbg, const picotrns_possym_t seq[], const picoos_uint16 seqLen); + +void picotrns_printSolution(const picotrns_possym_t outSeq[], const picoos_uint16 outSeqLen); + +#else +#define PICOTRNS_PRINTSYM(x,y) +#define PICOTRNS_PRINTSYMSEQ(x,y,z) +#define picotrns_printSolution NULL +#endif + + +typedef struct picotrns_altDesc * picotrns_AltDesc; + + +picotrns_AltDesc picotrns_allocate_alt_desc_buf(picoos_MemoryManager mm, picoos_uint32 maxByteSize, picoos_uint16 * numAltDescs); + +void picotrns_deallocate_alt_desc_buf(picoos_MemoryManager mm, picotrns_AltDesc * altDescBuf); + + +/* type of function for printing transduction solutions; + only for testing purposes in transduction mode where all solutions + are produced */ +typedef void picotrns_printSolutionFct(const picotrns_possym_t outSeq[], const picoos_uint16 outSeqLen); + + + +/** overall transduction; transduces 'inSeq' with 'inSeqLen' elements + to '*outSeqLen' elements in 'outSeq'; + * + * @param fst the finite-state transducer used for transduction + * @param firstSolOnly determines whether only the first solution (usually) + or all solutions should be produced (for testing); only the last found + solution is returned in 'outSeq'; + * @param printSolution if not NULL, every found solution is displayed using + the given function + * @param inSeq the input sequence + * @param inSeqLen the input sequence length + * @retval outSeq the output sequence + * @retval outSeqLen the output sequence length + * @param maxOutSeqLen must provide the maximum length of 'outSeq' + * @param altDescBuf must provide a working array of length 'maxAltDescLen' + * @param maxAltDescLen should be chosen at least 'maxOutSeqLen' + 1 + * @retval nrSteps returns the overall internal number of iterative steps done + * @return status of the transduction: PICO_OK, if transduction successful + @note if 'outSeq' or 'altDesc' are too small to hold a solution, + an error occurs and the input is simply transfered to the output + (up to maximum possible length) + */ +extern pico_status_t picotrns_transduce (picokfst_FST fst, picoos_bool firstSolOnly, + picotrns_printSolutionFct printSolution, + const picotrns_possym_t inSeq[], picoos_uint16 inSeqLen, + picotrns_possym_t outSeq[], picoos_uint16 * outSeqLen, picoos_uint16 maxOutSeqLen, + picotrns_AltDesc altDescBuf, picoos_uint16 maxAltDescLen, + picoos_uint32 *nrSteps); + + + +/* transduce 'inSeq' into 'outSeq' 'inSeq' has to be terminated with the id for symbol '#'. 'outSeq' is terminated in the same way. */ +/* +pico_status_t picotrns_transduce_sequence(picokfst_FST fst, const picotrns_possym_t inSeq[], picoos_uint16 inSeqLen, + picotrns_possym_t outSeq[], picoos_uint16 * outSeqLen); +*/ + +/* copy elements from inSeq to outSeq, ignoring elements with epsilon symbol */ +pico_status_t picotrns_eliminate_epsilons(const picotrns_possym_t inSeq[], picoos_uint16 inSeqLen, + picotrns_possym_t outSeq[], picoos_uint16 * outSeqLen, picoos_uint16 maxOutSeqLen); + +/* copy elements from inSeq to outSeq, inserting syllable separators in some trivial way. + * inSeq is assumed to be at most, outSeq at least of size PICOTRNS_MAX_NUM_POSSYM */ +pico_status_t picotrns_trivial_syllabify(picoktab_Phones phones, + const picotrns_possym_t inSeq[], const picoos_uint16 inSeqLen, + picotrns_possym_t outSeq[], picoos_uint16 * outSeqLen, picoos_uint16 maxOutSeqLen); + + +/** object : SimpleTransducer + * shortcut : st + * + */ +typedef struct picotrns_simple_transducer * picotrns_SimpleTransducer; + +picotrns_SimpleTransducer picotrns_newSimpleTransducer(picoos_MemoryManager mm, + picoos_Common common, + picoos_uint16 maxAltDescLen); + +pico_status_t picotrns_disposeSimpleTransducer(picotrns_SimpleTransducer * this, + picoos_MemoryManager mm); + +pico_status_t picotrns_stInitialize(picotrns_SimpleTransducer transducer); + +pico_status_t picotrns_stAddWithPlane(picotrns_SimpleTransducer this, picoos_char * inStr, picoos_uint8 plane); + +pico_status_t picotrns_stTransduce(picotrns_SimpleTransducer this, picokfst_FST fst); + +pico_status_t picotrns_stGetSymSequence( + picotrns_SimpleTransducer this, + picoos_uint8 * outputSymIds, + picoos_uint32 maxOutputSymIds); + + + + + +#ifdef __cplusplus +} +#endif + +#endif /*PICOTRNS_H_*/ diff --git a/pico/lib/picowa.c b/pico/lib/picowa.c new file mode 100644 index 0000000..edbff7d --- /dev/null +++ b/pico/lib/picowa.c @@ -0,0 +1,582 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picowa.c + * + * word analysis PU - lexicon lookup and POS prediction + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + +#include "picoos.h" +#include "picodbg.h" +#include "picodata.h" +#include "picowa.h" +#include "picoklex.h" +#include "picokdt.h" +#include "picoktab.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + +/* PU waStep states */ +#define WA_STEPSTATE_COLLECT 0 +#define WA_STEPSTATE_PROCESS 1 +#define WA_STEPSTATE_FEED 2 + + +/* subobject : WordAnaUnit + * shortcut : wa + * context size : one item + */ +typedef struct wa_subobj { + picoos_uint8 procState; /* for next processing step decision */ + + /* one item only */ + picoos_uint8 inBuf[PICOWA_MAXITEMSIZE]; /* internal input buffer */ + picoos_uint16 inBufSize; /* actually allocated size */ + picoos_uint16 inLen; /* length of item in inBuf, 0 for empty buf */ + + picoos_uint8 outBuf[PICOWA_MAXITEMSIZE]; /* internal output buffer */ + picoos_uint16 outBufSize; /* actually allocated size */ + picoos_uint16 outLen; /* length of item in outBuf, 0 for empty buf */ + + /* lex knowledge base */ + picoklex_Lex lex; + + /* ulex knowledge bases */ + picoos_uint8 numUlex; + picoklex_Lex ulex[PICOKNOW_MAX_NUM_ULEX]; + + /* tab knowledge base */ + picoktab_Pos tabpos; + + /* dtposp knowledge base */ + picokdt_DtPosP dtposp; +} wa_subobj_t; + + +static pico_status_t waInitialize(register picodata_ProcessingUnit this, picoos_int32 resetMode) { + picoos_uint8 i; + picoklex_Lex ulex; + wa_subobj_t * wa; + + picoknow_kb_id_t ulexKbIds[PICOKNOW_MAX_NUM_ULEX] = PICOKNOW_KBID_ULEX_ARRAY; + + PICODBG_DEBUG(("calling")); + + if (NULL == this || NULL == this->subObj) { + return (picodata_step_result_t) picoos_emRaiseException(this->common->em, + PICO_ERR_NULLPTR_ACCESS, NULL, NULL); + } + wa = (wa_subobj_t *) this->subObj; + wa->procState = WA_STEPSTATE_COLLECT; + wa->inBufSize = PICOWA_MAXITEMSIZE; + wa->inLen = 0; + wa->outBufSize = PICOWA_MAXITEMSIZE; + wa->outLen = 0; + + if (resetMode == PICO_RESET_SOFT) { + /*following initializations needed only at startup or after a full reset*/ + return PICO_OK; + } + /* kb lex */ + wa->lex = picoklex_getLex(this->voice->kbArray[PICOKNOW_KBID_LEX_MAIN]); + if (wa->lex == NULL) { + return picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + PICODBG_DEBUG(("got lex")); + + /* kb ulex[] */ + wa->numUlex = 0; + for (i = 0; ivoice->kbArray[ulexKbIds[i]]); + if (NULL != ulex) { + wa->ulex[wa->numUlex++] = ulex; + } + } + PICODBG_DEBUG(("got %i user lexica", wa->numUlex)); + + /* kb tabpos */ + wa->tabpos = + picoktab_getPos(this->voice->kbArray[PICOKNOW_KBID_TAB_POS]); + if (wa->tabpos == NULL) { + return picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + PICODBG_DEBUG(("got tabpos")); + + /* kb dtposp */ + wa->dtposp = picokdt_getDtPosP(this->voice->kbArray[PICOKNOW_KBID_DT_POSP]); + if (wa->dtposp == NULL) { + return picoos_emRaiseException(this->common->em, PICO_EXC_KB_MISSING, + NULL, NULL); + } + PICODBG_DEBUG(("got dtposp")); + return PICO_OK; +} + +static picodata_step_result_t waStep(register picodata_ProcessingUnit this, + picoos_int16 mode, + picoos_uint16 *numBytesOutput); + +static pico_status_t waTerminate(register picodata_ProcessingUnit this) { + return PICO_OK; +} + +static pico_status_t waSubObjDeallocate(register picodata_ProcessingUnit this, + picoos_MemoryManager mm) { + if (NULL != this) { + picoos_deallocate(this->common->mm, (void *) &this->subObj); + } + mm = mm; /* avoid warning "var not used in this function"*/ + return PICO_OK; +} + + +picodata_ProcessingUnit picowa_newWordAnaUnit(picoos_MemoryManager mm, + picoos_Common common, + picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, + picorsrc_Voice voice) { + picodata_ProcessingUnit this; + + this = picodata_newProcessingUnit(mm, common, cbIn, cbOut, voice); + if (this == NULL) { + return NULL; + } + + this->initialize = waInitialize; + PICODBG_DEBUG(("set this->step to waStep")); + this->step = waStep; + this->terminate = waTerminate; + this->subDeallocate = waSubObjDeallocate; + this->subObj = picoos_allocate(mm, sizeof(wa_subobj_t)); + if (this->subObj == NULL) { + picoos_deallocate(mm, (void *)&this); + picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM, NULL, NULL); + return NULL; + } + + waInitialize(this, PICO_RESET_FULL); + return this; +} + +/* ***********************************************************************/ +/* WORDGRAPH proc functions */ +/* ***********************************************************************/ + +static picoos_uint8 waClassifyPos(register picodata_ProcessingUnit this, + register wa_subobj_t *wa, + const picoos_uint8 *graph, + const picoos_uint16 graphlen) { + picokdt_classify_result_t dtres; + picoos_uint8 specchar; + picoos_uint16 i; + + PICODBG_DEBUG(("graphlen %d", graphlen)); + + /* check existence of special char (e.g. hyphen) in graph: + for now, check existence of hard-coded ascii hyphen, + ie. preproc needs to match all UTF8 hyphens to the ascii + hyphen. */ + /* @todo : consider specifying special char(s) in lingware. */ + specchar = FALSE; + i = 0; + while ((i < graphlen) && (!specchar)) { + if (graph[i++] == '-') { + specchar = TRUE; + } + } + + /* construct input vector, which is set in dtposp */ + if (!picokdt_dtPosPconstructInVec(wa->dtposp, graph, graphlen, specchar)) { + /* error constructing invec */ + PICODBG_WARN(("problem with invec")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_INVECTOR, NULL, NULL); + return PICODATA_ITEMINFO1_ERR; + } + + /* classify */ + if (!picokdt_dtPosPclassify(wa->dtposp)) { + /* error doing classification */ + PICODBG_WARN(("problem classifying")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_CLASSIFICATION, + NULL, NULL); + return PICODATA_ITEMINFO1_ERR; + } + + /* decompose */ + if (!picokdt_dtPosPdecomposeOutClass(wa->dtposp, &dtres)) { + /* error decomposing */ + PICODBG_WARN(("problem decomposing")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_OUTVECTOR, + NULL, NULL); + return PICODATA_ITEMINFO1_ERR; + } + + if (dtres.set) { + PICODBG_DEBUG(("class %d", dtres.class)); + return (picoos_uint8)dtres.class; + } else { + PICODBG_WARN(("result not set")); + picoos_emRaiseWarning(this->common->em, PICO_WARN_CLASSIFICATION, + NULL, NULL); + return PICODATA_ITEMINFO1_ERR; + } +} + + +static pico_status_t waProcessWordgraph(register picodata_ProcessingUnit this, + register wa_subobj_t *wa /*inout*/, + picodata_itemhead_t *head /*inout*/, + const picoos_uint8 *content) { + pico_status_t status; + picoklex_lexl_result_t lexres; + picoos_uint8 posbuf[PICOKTAB_MAXNRPOS_IN_COMB]; + picoos_uint8 i; + picoos_uint8 foundIndex; + picoos_bool found; + + + PICODBG_DEBUG(("type %c, len %d", head->type, head->len)); + + /* do lookup + if no entry found: + do POS prediction: -> WORDGRAPH(POSes,NA)graph + else: + if incl-phone: + N entries possible -> WORDINDEX(POSes,NA)POS1|ind1...POSN|indN + (N in {1,...,PICOKLEX_MAX_NRRES}, now up to 4) + else: + no phone, one entry -> WORDGRAPH(POS,NA)graph + */ + + found = FALSE; + i = 0; + while (!found && (i < wa->numUlex)) { + found = picoklex_lexLookup(wa->ulex[i], content, head->len, &lexres); + i++; + } + /* note that if found, i will be incremented nevertheless, so i >= 1 */ + if (found) { + foundIndex = i; + } else { + foundIndex = 0; + } + if (!found && !picoklex_lexLookup(wa->lex, content, head->len, &lexres)) { + /* no lex entry found, WORDGRAPH(POS,NA)graph */ + if (PICO_OK == picodata_copy_item(wa->inBuf, wa->inLen, + wa->outBuf, wa->outBufSize, + &wa->outLen)) { + wa->inLen = 0; + /* predict and modify pos in info1 */ + if (PICO_OK != picodata_set_iteminfo1(wa->outBuf, wa->outLen, + waClassifyPos(this, wa, content, head->len))) { + return picoos_emRaiseException(this->common->em, + PICO_EXC_BUF_OVERFLOW,NULL,NULL); + } + } + + } else { /* at least one entry found */ + PICODBG_DEBUG(("at least one entry found in lexicon %i",foundIndex)); + if (lexres.phonfound) { /* incl. ind-phone and possibly multi-ent. */ + if (lexres.nrres > PICOKLEX_MAX_NRRES) { + /* not possible with system lexicon, needs to be + ensured for user lex too */ + picoos_emRaiseWarning(this->common->em, PICO_WARN_FALLBACK,NULL, + (picoos_char *)"using %d lexicon lookup results", + PICOKLEX_MAX_NRRES); + lexres.nrres = PICOKLEX_MAX_NRRES; + } + head->type = PICODATA_ITEM_WORDINDEX; + if (lexres.nrres == 1) { + head->info1 = lexres.posind[0]; + } else { + /* more than one result, POSgroup info needs to be + determined for later POS disambiguation */ + for (i = 0; i < lexres.nrres; i++) { + posbuf[i] = lexres.posind[i * PICOKLEX_POSIND_SIZE]; + } + head->info1 = picoktab_getPosGroup(wa->tabpos, posbuf, + lexres.nrres); + } + head->info2 = foundIndex; + head->len = lexres.posindlen; + if ((status = picodata_put_itemparts(head, lexres.posind, + lexres.posindlen, + wa->outBuf, wa->outBufSize, + &wa->outLen)) == PICO_OK) { + wa->inLen = 0; + } else { + return picoos_emRaiseException(this->common->em, status, + NULL, NULL); + } + + } else { /* no phone, :G2P, one entry: WORDGRAPH(POS,NA)graph */ + if (PICO_OK == picodata_copy_item(wa->inBuf, wa->inLen, + wa->outBuf, wa->outBufSize, + &wa->outLen)) { + wa->inLen = 0; + /* set lex pos in info1 */ + if (PICO_OK != picodata_set_iteminfo1(wa->outBuf, wa->outLen, + lexres.posind[0])) { + return picoos_emRaiseException(this->common->em, + PICO_EXC_BUF_OVERFLOW, + NULL, NULL); + } + } + } + } + return PICO_OK; +} + + +/* ***********************************************************************/ +/* waStep function */ +/* ***********************************************************************/ + +/* + collect into internal buffer, process, and then feed to output buffer + + init state: COLLECT ext ext + state transitions: in IN OUTout + COLLECT | getOneItem ->-1 +1 0 0 | (ATOMIC) -> PROCESS (got item) + COLLECT | getOneItem -> 0 0 0 0 | IDLE (got no item) + + PROCESS | procOneItem -> 0 -1 +1 0 | (ATOMIC) -> FEED (proc'ed item) + PROCESS | procOneItem -> 0 -1 0 0 | BUSY -> COLLECT (item skipped) + + FEED | putOneItem -> 0 0 -1 +1 | BUSY -> COLLECT (put item) + FEED | putOneItem -> 0 0 1 0 | OUT_FULL (put no item) +*/ + +static picodata_step_result_t waStep(register picodata_ProcessingUnit this, + picoos_int16 mode, + picoos_uint16 * numBytesOutput) { + register wa_subobj_t *wa; + pico_status_t rv = PICO_OK; + + if (NULL == this || NULL == this->subObj) { + return PICODATA_PU_ERROR; + } + wa = (wa_subobj_t *) this->subObj; + mode = mode; /* avoid warning "var not used in this function"*/ + *numBytesOutput = 0; + while (1) { /* exit via return */ + PICODBG_DEBUG(("doing state %i, inLen: %d, outLen: %d", + wa->procState, wa->inLen, wa->outLen)); + + switch (wa->procState) { + /* collect state: get item from charBuf and store in + * internal inBuf + */ + case WA_STEPSTATE_COLLECT: + if (wa->inLen == 0) { /* is input buffer empty? */ + picoos_uint16 blen; + /* try to get one item */ + rv = picodata_cbGetItem(this->cbIn, wa->inBuf, + wa->inBufSize, &blen); + PICODBG_DEBUG(("after getting item, status: %d", rv)); + if (PICO_OK == rv) { + /* we now have one item */ + wa->inLen = blen; + wa->procState = WA_STEPSTATE_PROCESS; + /* uncomment next line to split into two steps */ + /* return PICODATA_PU_ATOMIC; */ + } else if (PICO_EOF == rv) { + /* there was no item in the char buffer */ + return PICODATA_PU_IDLE; + } else if ((PICO_EXC_BUF_UNDERFLOW == rv) + || (PICO_EXC_BUF_OVERFLOW == rv)) { + PICODBG_ERROR(("problem getting item")); + picoos_emRaiseException(this->common->em, rv, + NULL, NULL); + return PICODATA_PU_ERROR; + } else { + PICODBG_ERROR(("problem getting item, unhandled")); + picoos_emRaiseException(this->common->em, rv, + NULL, NULL); + return PICODATA_PU_ERROR; + } + } else { /* there already is an item in the input buffer */ + PICODBG_WARN(("item already in input buffer")); + picoos_emRaiseWarning(this->common->em, + PICO_WARN_PU_IRREG_ITEM, NULL, NULL); + wa->procState = WA_STEPSTATE_PROCESS; + /* uncomment next to split into two steps */ + /* return PICODATA_PU_ATOMIC; */ + } + break; + + + /* process state: process item in internal inBuf and put + * result in internal outBuf + */ + case WA_STEPSTATE_PROCESS: + + /* ensure there is an item in inBuf and it is valid */ + if ((wa->inLen > 0) && picodata_is_valid_item(wa->inBuf, + wa->inLen)) { + picodata_itemhead_t ihead; + picoos_uint8 *icontent; + pico_status_t rvP = PICO_OK; + + rv = picodata_get_iteminfo(wa->inBuf, wa->inLen, &ihead, + &icontent); + if (PICO_OK == rv) { + + switch (ihead.type) { + case PICODATA_ITEM_WORDGRAPH: + + if (0 < ihead.len) { + rvP = waProcessWordgraph(this, wa, &ihead, + icontent); + } else { + /* else ignore empty WORDGRAPH */ + wa->inLen = 0; + wa->procState = WA_STEPSTATE_COLLECT; + return PICODATA_PU_BUSY; + } + break; + case PICODATA_ITEM_OTHER: + /* skip item */ + rvP = PICO_WARN_PU_DISCARD_BUF; + break; + default: + /* copy item unmodified */ + rvP = picodata_copy_item(wa->inBuf, + wa->inLen, wa->outBuf, + wa->outBufSize, &wa->outLen); + break; + } + + if (PICO_OK == rvP) { + wa->inLen = 0; + wa->procState = WA_STEPSTATE_FEED; + /* uncomment next to split into two steps */ + /* return PICODATA_PU_ATOMIC; */ + } else if (PICO_WARN_PU_DISCARD_BUF == rvP) { + /* discard input buffer and get a new item */ + PICODBG_INFO(("skipping OTHER item")); +/* picoos_emRaiseWarning(this->common->em, + PICO_WARN_PU_DISCARD_BUF, NULL, NULL); +*/ + wa->inLen = 0; + wa->procState = WA_STEPSTATE_COLLECT; + return PICODATA_PU_BUSY; + } else { + /* PICO_EXC_BUF_OVERFLOW <- overflow in outbuf + PICO_ERR_OTHER <- no valid item in inbuf + or return from processWordgraph + */ + PICODBG_ERROR(("problem processing item", rvP)); + picoos_emRaiseException(this->common->em, rvP, + NULL, NULL); + return PICODATA_PU_ERROR; + } + + } else { /* could not get iteminfo */ + /* PICO_EXC_BUF_OVERFLOW <- overflow in outbuf + PICO_ERR_OTHER <- no valid item in inbuf + */ + PICODBG_ERROR(("problem getting item info, " + "discard buffer content")); + wa->inLen = 0; + wa->procState = WA_STEPSTATE_COLLECT; + picoos_emRaiseException(this->common->em, rv, + NULL, NULL); + return PICODATA_PU_ERROR; + } + + } else if (wa->inLen == 0) { /* no item in inBuf */ + PICODBG_INFO(("no item in inBuf")); + /* wa->inLen = 0;*/ + wa->procState = WA_STEPSTATE_COLLECT; + return PICODATA_PU_BUSY; + + } else { /* no valid item in inBuf */ + /* bad state/item, discard buffer content */ + PICODBG_WARN(("no valid item, discard buffer content")); + picoos_emRaiseWarning(this->common->em, + PICO_WARN_PU_IRREG_ITEM, NULL, NULL); + picoos_emRaiseWarning(this->common->em, + PICO_WARN_PU_DISCARD_BUF, NULL, NULL); + wa->inLen = 0; + wa->procState = WA_STEPSTATE_COLLECT; + return PICODATA_PU_BUSY; + } + break; + + + /* feed state: copy item in internal outBuf to output charBuf */ + case WA_STEPSTATE_FEED: + + /* check that item fits in cb should not be needed */ + rv = picodata_cbPutItem(this->cbOut, wa->outBuf, + wa->outLen, numBytesOutput); + + PICODATA_INFO_ITEM(this->voice->kbArray[PICOKNOW_KBID_DBG], + (picoos_uint8 *)"wana: ", wa->outBuf, + wa->outLen); + + PICODBG_DEBUG(("put item, status: %d", rv)); + if (PICO_OK == rv) { + wa->outLen = 0; + wa->procState = WA_STEPSTATE_COLLECT; + return PICODATA_PU_BUSY; + } else if (PICO_EXC_BUF_OVERFLOW == rv) { + PICODBG_INFO(("feeding, overflow, PICODATA_PU_OUT_FULL")); + return PICODATA_PU_OUT_FULL; + } else if ((PICO_EXC_BUF_UNDERFLOW == rv) + || (PICO_ERR_OTHER == rv)) { + PICODBG_WARN(("feeding problem, discarding item")); + wa->outLen = 0; + wa->procState = WA_STEPSTATE_COLLECT; + picoos_emRaiseWarning(this->common->em, rv, NULL,NULL); + return PICODATA_PU_BUSY; + } + break; + + default: + break; + + } /* switch */ + + } /* while */ + + /* should be never reached */ + PICODBG_ERROR(("reached end of function")); + picoos_emRaiseException(this->common->em, PICO_ERR_OTHER, NULL, NULL); + return PICODATA_PU_ERROR; +} + +#ifdef __cplusplus +} +#endif + + +/* end */ diff --git a/pico/lib/picowa.h b/pico/lib/picowa.h new file mode 100644 index 0000000..d7fbcd3 --- /dev/null +++ b/pico/lib/picowa.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file picowa.h + * + * Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland + * All rights reserved. + * + * History: + * - 2009-04-20 -- initial version + * + */ + + +/** + * @addtogroup picowa + * ---------------------------------------------------\n + * Pico Word Analysis \n + * ---------------------------------------------------\n +itemtype, iteminfo1, iteminfo2, content -> TYPE(INFO1,INFO2)content +in the following + +items input\n +=========== + +processed by wa: +- WORDGRAPH(NA,NA)graph +- OTHER(NA,NA)string + +unprocessed: +- all other item types are forwarded through the PU without modification: + - PUNC + - CMD + + +minimal input size (before processing starts)\n +================== + +processing (ie. lex lookup and POS prediction) is possible with +- one item + + +items processed and output\n +========================== + +processing an input WORDGRAPH results in one of the following items: +- WORDGRAPH(POSes,NA)graph + - graph not in lex, POSes determined with dtree, or + - graph in lex - single entry without phone (:G2P), POSes from lex +- WORDINDEX(POSes,NA)pos1|ind1...posN|indN + - graph in lex - {1,4} entries with phone, pos1...posN from lex, + {1,4} lexentries indices in content, POSes combined with map table + in klex + +processing an input OTHER results in the item being skipped (in the +future this can be extended to e.g. spelling) + +see picotok.h for PUNC and CMD + +- POSes %d + - is the superset of all single POS and POS combinations defined + in the lingware as unique symbol +- graph, len>0, utf8 graphemes, %s +- pos1|ind1, pos2|ind2, ..., posN|indN + - pos? are the single, unambiguous POS only, one byte %d + - ind? are the lexentry indices, three bytes %d %d %d + + +lexicon (system lexicon, but must also be ensured for user lexica)\n +======= + +- POS GRAPH PHON, all mandatory, but + - * PHON can be an empty string -> no pronunciation in the resulting TTS output + - * PHON can be :G2P -> use G2P later to add pronunciation +- (POS,GRAPH) is a uniq key (only one entry allowed) +- (GRAPH) is almost a uniq key (2-4 entries with the same GRAPH, and + differing POS and differing PHON possible) + - for one graph we can have 2-4 solutions from the lex which all + need to be passed on the the next PU + - in this case GRAPH, POS, and PHON all must be available in lex + - in this case for each entry only a non-ambiguous, unique POS ID + is possible) + +other limitations\n +================= + +- item size: header plus len=256 (valid for Pico in general) +- wa uses one item context only -> internal buffer set to 256+4 + */ + + +#ifndef PICOWA_H_ +#define PICOWA_H_ + +#include "picoos.h" +#include "picodata.h" +#include "picorsrc.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} +#endif + + +/* maximum length of an item incl. head for input and output buffers */ +#define PICOWA_MAXITEMSIZE 260 + + +picodata_ProcessingUnit picowa_newWordAnaUnit( + picoos_MemoryManager mm, + picoos_Common common, + picodata_CharBuffer cbIn, + picodata_CharBuffer cbOut, + picorsrc_Voice voice); + +#ifdef __cplusplus +} +#endif + +#endif /*PICOWA_H_*/