diff options
| author | Piotr Pawlow <pp@siedziba.pl> | 2014-03-13 20:51:31 +0100 |
|---|---|---|
| committer | Piotr Pawlow <pp@siedziba.pl> | 2014-03-13 20:51:31 +0100 |
| commit | c04af18902322cea1bd05b6f01b7860ca7bfa432 (patch) | |
| tree | d8d3f812112c0cc835fd29e68d92e297e0164b52 /src/lingot-config.c | |
- import version 0.9.1 from upstream
Diffstat (limited to 'src/lingot-config.c')
| -rw-r--r-- | src/lingot-config.c | 458 |
1 files changed, 458 insertions, 0 deletions
diff --git a/src/lingot-config.c b/src/lingot-config.c new file mode 100644 index 0000000..e0a1343 --- /dev/null +++ b/src/lingot-config.c @@ -0,0 +1,458 @@ +/* + * lingot, a musical instrument tuner. + * + * Copyright (C) 2004-2011 Ibán Cereijo Graña, Jairo Chapela Martínez. + * + * This file is part of lingot. + * + * lingot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * lingot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with lingot; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <locale.h> + +#include "lingot-defs.h" +#include "lingot-config.h" +#include "lingot-config-scale.h" +#include "lingot-msg.h" +#include "lingot-i18n.h" + +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#define N_OPTIONS 20 + +// the following tokens will appear in the config file. The options after | are deprecated options. +char* options[] = { "AUDIO_SYSTEM", "AUDIO_DEV", "AUDIO_DEV_ALSA", + "SAMPLE_RATE", "OVERSAMPLING", "ROOT_FREQUENCY_ERROR", "MIN_FREQUENCY", + "FFT_SIZE", "TEMPORAL_WINDOW", "NOISE_THRESHOLD", "CALCULATION_RATE", + "VISUALIZATION_RATE", "PEAK_NUMBER", "PEAK_HALF_WIDTH", + "PEAK_REJECTION_RELATION", "DFT_NUMBER", "DFT_SIZE", "GAIN", "|", + "PEAK_ORDER", NULL // NULL terminated array + }; + +// print/scan param formats. +const char* option_formats = "mssddffdffffddfddf|d"; + +// converts an audio_system_t to a string +const char* audio_system_t_to_str(audio_system_t audio_system) { + const char* values[] = { "OSS", "ALSA", "JACK" }; + return values[audio_system]; +} + +// converts a string to an audio_system_t +audio_system_t str_to_audio_system_t(char* audio_system) { + audio_system_t result = -1; + const char* values[] = { "OSS", "ALSA", "JACK", NULL }; + int i; + for (i = 0; values[i] != NULL; i++) { + if (!strcmp(audio_system, values[i])) { + result = i; + break; + } + } + return result; +} + +//---------------------------------------------------------------------------- + +LingotConfig* lingot_config_new() { + + LingotConfig* config = malloc(sizeof(LingotConfig)); + + config->max_nr_iter = 10; // iterations + config->window_type = HAMMING; + config->scale = lingot_config_scale_new(); + return config; +} + +void lingot_config_destroy(LingotConfig* config) { + lingot_config_scale_destroy(config->scale); + free(config->scale); + free(config); +} + +void lingot_config_copy(LingotConfig* dst, LingotConfig* src) { + LingotScale* dst_scale = dst->scale; + *dst = *src; + dst->scale = dst_scale; + lingot_config_scale_copy(dst->scale, src->scale); +} + +//---------------------------------------------------------------------------- + +void lingot_config_restore_default_values(LingotConfig* config) { + + config->audio_system = AUDIO_SYSTEM_ALSA; + sprintf(config->audio_dev[AUDIO_SYSTEM_OSS], "%s", "/dev/dsp"); + sprintf(config->audio_dev[AUDIO_SYSTEM_ALSA], "%s", "plughw:0"); + + config->sample_rate = 44100; // Hz + config->oversampling = 25; + config->root_frequency_error = 0; // Hz + config->min_frequency = 15; // Hz + config->fft_size = 512; // samples + config->temporal_window = 0.32; // seconds + config->calculation_rate = 20; // Hz + config->visualization_rate = 30; // Hz + config->noise_threshold_db = 20.0; // dB + config->gain = 0; + + config->peak_number = 3; // peaks + config->peak_half_width = 1; // samples + config->peak_rejection_relation_db = 20; // dB + + config->dft_number = 2; // DFTs + config->dft_size = 15; // samples + + //-------------------------------------------------------------------------- + + lingot_config_scale_restore_default_values(config->scale); + lingot_config_update_internal_params(config); +} + +//---------------------------------------------------------------------------- + +void lingot_config_update_internal_params(LingotConfig* config) { + + // derived parameters. + config->temporal_buffer_size = (unsigned int) ceil(config->temporal_window + * config->sample_rate / config->oversampling); + config->peak_rejection_relation_nu = pow(10.0, + config->peak_rejection_relation_db / 10.0); + config->noise_threshold_nu = pow(10.0, config->noise_threshold_db / 10.0); + config->gain_nu = pow(10.0, config->gain / 20.0); + + LingotScale* scale = config->scale; + if (scale->notes == 1) { + scale->max_offset_rounded = 1200.0; + } else { + int i; + FLT max_offset = 0.0; + for (i = 1; i < scale->notes; i++) { + max_offset = MAX(max_offset, scale->offset_cents[i] + - scale->offset_cents[i - 1]); + } + scale->max_offset_rounded = max_offset; + } + + config->gauge_rest_value = -0.45 * scale->max_offset_rounded; + sprintf(config->audio_dev[AUDIO_SYSTEM_JACK], "%s", ""); +} + +//---------------------------------------------------------------------------- + +// internal parameters mapped to each token in the config file. +void lingot_map_parameters(LingotConfig* config, void* params[]) { + void* c_params[] = { &config->audio_system, + &config->audio_dev[AUDIO_SYSTEM_OSS], + &config->audio_dev[AUDIO_SYSTEM_ALSA], &config->sample_rate, + &config->oversampling, &config->root_frequency_error, + &config->min_frequency, &config->fft_size, + &config->temporal_window, &config->noise_threshold_db, + &config->calculation_rate, &config->visualization_rate, + &config->peak_number, &config->peak_half_width, + &config->peak_rejection_relation_db, &config->dft_number, + &config->dft_size, &config->gain, NULL, &config->peak_half_width }; + + memcpy(params, c_params, N_OPTIONS * sizeof(void*)); +} + +void lingot_config_save(LingotConfig* config, char* filename) { + unsigned int i; + FILE* fp; + char* lc_all; + void* params[N_OPTIONS]; // parameter pointer array. + void* param = NULL; + char* option = NULL; + char buff[80]; + + lingot_map_parameters(config, params); + + lc_all = setlocale(LC_ALL, NULL); + // duplicate the string, as the next call to setlocale will destroy it + if (lc_all) + lc_all = strdup(lc_all); + setlocale(LC_ALL, "C"); + + if ((fp = fopen(filename, "w")) == NULL) { + char buff[100]; + sprintf(buff, "error saving config file %s ", filename); + perror(buff); + return; + } + + fprintf(fp, "# Config file automatically created by lingot %s\n\n", VERSION); + + for (i = 0; strcmp(options[i], "|"); i++) { + + option = options[i]; + param = params[i]; + + switch (option_formats[i]) { + case 's': + fprintf(fp, "%s = %s\n", option, (char*) param); + break; + case 'd': + fprintf(fp, "%s = %d\n", option, *((unsigned int*) param)); + break; + case 'f': + fprintf(fp, "%s = %0.3f\n", option, *((FLT*) param)); + break; + case 'm': + if (!strcmp("AUDIO_SYSTEM", option)) { + fprintf(fp, "%s = %s\n", option, audio_system_t_to_str( + *((audio_system_t*) param))); + } + break; + } + } + + fprintf(fp, "\n"); + fprintf(fp, "SCALE = {\n"); + fprintf(fp, "NAME = %s\n", config->scale->name); + fprintf(fp, "BASE_FREQUENCY = %f\n", config->scale->base_frequency); + fprintf(fp, "NOTE_COUNT = %d\n", config->scale->notes); + fprintf(fp, "NOTES = {\n"); + + for (i = 0; i < config->scale->notes; i++) { + lingot_config_scale_format_shift(buff, config->scale->offset_cents[i], + config->scale->offset_ratios[0][i], + config->scale->offset_ratios[1][i]); + fprintf(fp, "%s\t%s\n", config->scale->note_name[i], buff); + } + + fprintf(fp, "}\n"), fprintf(fp, "}\n"), + + fclose(fp); + + if (lc_all) { + setlocale(LC_ALL, lc_all); + free(lc_all); + } +} + +//---------------------------------------------------------------------------- + +void lingot_config_load(LingotConfig* config, char* filename) { + FILE* fp; + float aux; + int line; + int option_index; + int deprecated_option = 0; + char* char_buffer_pointer; + const static char* delim = " \t=\n"; + const static char* delim2 = " \t\n"; + void* params[N_OPTIONS]; // parameter pointer array. + void* param = NULL; + char* option = NULL; + int reading_scale = 0; + char* nl; + int parse_errors = 0; + int command_count = 0; + + // restore default values for non specified parameters + lingot_config_restore_default_values(config); + + lingot_map_parameters(config, params); + +# define MAX_LINE_SIZE 100 + + char char_buffer[MAX_LINE_SIZE]; + + if ((fp = fopen(filename, "r")) == NULL) { + sprintf(char_buffer, + "error opening config file %s, assuming default values ", + filename); + perror(char_buffer); + return; + } + + line = 0; + + for (;;) { + + line++; + + if (!fgets(char_buffer, MAX_LINE_SIZE, fp)) + break;; + + if (char_buffer[0] == '#') + continue; + + // tokens into the line. + char_buffer_pointer = strtok(char_buffer, delim); + + if (!char_buffer_pointer) + continue; // blank line. + + + if (!strcmp(char_buffer_pointer, "SCALE")) { + reading_scale = 1; + config->scale = lingot_config_scale_new(); + command_count++; + continue; + } + + if (reading_scale) { + + if (!strcmp(char_buffer_pointer, "NAME")) { + char_buffer_pointer += 4; + while (1) { + nl = strchr(delim, *char_buffer_pointer); + if (!nl) + break; + char_buffer_pointer++; + } + nl = strrchr(char_buffer_pointer, '\r'); + if (nl) + *nl = '\0'; + nl = strrchr(char_buffer_pointer, '\n'); + if (nl) + *nl = '\0'; + config->scale->name = strdup(char_buffer_pointer); + continue; + } + if (!strcmp(char_buffer_pointer, "BASE_FREQUENCY")) { + char_buffer_pointer = strtok(NULL, delim); + sscanf(char_buffer_pointer, "%lg", + &config->scale->base_frequency); + continue; + } + if (!strcmp(char_buffer_pointer, "NOTE_COUNT")) { + char_buffer_pointer = strtok(NULL, delim); + sscanf(char_buffer_pointer, "%hu", &config->scale->notes); + lingot_config_scale_allocate(config->scale, + config->scale->notes); + continue; + } + + if (!strcmp(char_buffer_pointer, "NOTES")) { + int i = 0; + for (i = 0; i < config->scale->notes; i++) { + line++; + if (!fgets(char_buffer, MAX_LINE_SIZE, fp)) + break; + // tokens into the line. + char_buffer_pointer = strtok(char_buffer, delim2); + config->scale->note_name[i] = strdup(char_buffer_pointer); + char_buffer_pointer = strtok(NULL, delim2); + if (!lingot_config_scale_parse_shift(char_buffer_pointer, + &config->scale->offset_cents[i], + &config->scale->offset_ratios[0][i], + &config->scale->offset_ratios[1][i])) { + parse_errors = 1; + } + } + line++; + if (!fgets(char_buffer, MAX_LINE_SIZE, fp)) + break; // } + + continue; + } + + if (!strcmp(char_buffer_pointer, "}")) { + reading_scale = 0; + continue; + } + + } + + deprecated_option = 0; + for (option_index = 0; options[option_index]; option_index++) { + if (!strcmp(char_buffer_pointer, options[option_index])) { + break; // found token. + } else if (!strcmp("|", options[option_index])) { + deprecated_option = 1; + } + } + + option = options[option_index]; + param = params[option_index]; + + if (!option) { + fprintf(stderr, + "warning: parse error at line %i: unknown keyword %s\n", + line, char_buffer_pointer); + parse_errors = 1; + continue; + } + + if (deprecated_option) { + fprintf(stdout, "warning: deprecated option %s\n", + char_buffer_pointer); + } + + // take the attribute value. + char_buffer_pointer = strtok(NULL, delim); + + if (!char_buffer_pointer) { + fprintf(stderr, + "warning: parse error at line %i: value expected\n", line); + parse_errors = 1; + continue; + } + + // asign the value to the parameter. + switch (option_formats[option_index]) { + case 's': + sprintf(((char*) param), "%s", char_buffer_pointer); + command_count++; + break; + case 'd': + sscanf(char_buffer_pointer, "%d", (unsigned int*) param); + command_count++; + break; + case 'f': + sscanf(char_buffer_pointer, "%f", &aux); + *((FLT*) param) = aux; + command_count++; + break; + case 'm': + if (!strcmp("AUDIO_SYSTEM", option)) { + command_count++; + *((audio_system_t*) param) = str_to_audio_system_t( + char_buffer_pointer); + if (*((audio_system_t*) param) == (audio_system_t) -1) { + *((audio_system_t*) param) = AUDIO_SYSTEM_ALSA; + char buff[1000]; + sprintf( + buff, + _( + "Error parsing the configuration file, line %i: unrecognized audio system '%s', assuming default audio system.\n"), + line, char_buffer_pointer); + + lingot_msg_add_warning(buff); + parse_errors = 1; + } + } + break; + } + } + + fclose(fp); + + if (parse_errors) { + lingot_msg_add_warning( + _( + "The configuration file contains errors, and hence some default values have been chosen. Consider checking the settings and fixing the problem using the configuration dialog.")); + } + + lingot_config_update_internal_params(config); + +# undef MAX_LINE_SIZE +} |
