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-scale.c | |
- import version 0.9.1 from upstream
Diffstat (limited to 'src/lingot-config-scale.c')
| -rw-r--r-- | src/lingot-config-scale.c | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/src/lingot-config-scale.c b/src/lingot-config-scale.c new file mode 100644 index 0000000..17f0415 --- /dev/null +++ b/src/lingot-config-scale.c @@ -0,0 +1,255 @@ +/* + * 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 <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> + +#include "lingot-config-scale.h" + +LingotScale* lingot_config_scale_new() { + + LingotScale* scale = malloc(sizeof(LingotScale)); + + scale->name = NULL; + scale->notes = 0; + scale->note_name = NULL; + scale->offset_cents = NULL; + scale->offset_ratios[0] = NULL; + scale->offset_ratios[1] = NULL; + scale->base_frequency = 0.0; + + return scale; +} + +void lingot_config_scale_allocate(LingotScale* scale, unsigned short int notes) { + scale->notes = notes; + scale->note_name = malloc(notes * sizeof(char*)); + scale->offset_cents = malloc(notes * sizeof(FLT)); + scale->offset_ratios[0] = malloc(notes * sizeof(short int)); + scale->offset_ratios[1] = malloc(notes * sizeof(short int)); +} + +void lingot_config_scale_destroy(LingotScale* scale) { + unsigned short int i; + for (i = 0; i < scale->notes; i++) { + free(scale->note_name[i]); + } + + if (scale->offset_cents != NULL) + free(scale->offset_cents); + + if (scale->offset_ratios[0] != NULL) + free(scale->offset_ratios[0]); + if (scale->offset_ratios[1] != NULL) + free(scale->offset_ratios[1]); + + if (scale->note_name != NULL) + free(scale->note_name); + if (scale->name != NULL) + free(scale->name); + + scale->name = NULL; + scale->notes = 0; + scale->note_name = NULL; + scale->offset_cents = NULL; + scale->offset_ratios[0] = NULL; + scale->offset_ratios[1] = NULL; + scale->base_frequency = 0.0; +} + +void lingot_config_scale_restore_default_values(LingotScale* scale) { + + unsigned short int i; + static char* tone_string[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", + "G#", "A", "A#", "B", }; + + lingot_config_scale_destroy(scale); + + // default 12 tones equal-tempered scale hard-coded + scale->name = strdup("Default equal-tempered scale"); + lingot_config_scale_allocate(scale, 12); + + scale->base_frequency = MID_C_FREQUENCY; + + scale->note_name[0] = strdup(tone_string[0]); + scale->offset_cents[0] = 0.0; + scale->offset_ratios[0][0] = 1; + scale->offset_ratios[1][0] = 1; // 1/1 + + for (i = 1; i < scale->notes; i++) { + scale->note_name[i] = strdup(tone_string[i]); + scale->offset_cents[i] = 100.0 * i; + scale->offset_ratios[0][i] = -1; // not used + scale->offset_ratios[1][i] = -1; // not used + } +} + +void lingot_config_scale_copy(LingotScale* dst, LingotScale* src) { + unsigned short int i; + + lingot_config_scale_destroy(dst); + + *dst = *src; + + dst->name = strdup(src->name); + lingot_config_scale_allocate(dst, dst->notes); + + for (i = 0; i < dst->notes; i++) { + dst->note_name[i] = strdup(src->note_name[i]); + dst->offset_cents[i] = src->offset_cents[i]; + dst->offset_ratios[0][i] = src->offset_ratios[0][i]; + dst->offset_ratios[1][i] = src->offset_ratios[1][i]; + } +} + +int lingot_config_scale_parse_shift(char* char_buffer, double* cents, + short int* numerator, short int* denominator) { + const static char* delim = "/"; + char* char_buffer_pointer1 = strtok(char_buffer, delim); + char* char_buffer_pointer2 = strtok(NULL, delim); + short int num, den; + int result = 1; + + if (numerator != NULL) { + *numerator = -1; + } + + if (denominator != NULL) { + *denominator = -1; + } + + int n = 0; + if (!char_buffer_pointer2) { + n = sscanf(char_buffer_pointer1, "%lf", cents); + if (!n) { + result = 0; + } + } else { + n = sscanf(char_buffer_pointer1, "%hd", &num); + if (!n) { + result = 0; + } else { + n = sscanf(char_buffer_pointer2, "%hd", &den); + if (!n) { + result = 0; + } else { + *cents = 1200.0 * log2(1.0 * num / den); + if (numerator != NULL) { + *numerator = num; + } + if (denominator != NULL) { + *denominator = den; + } + } + } + } + + if (!result) { + *numerator = 1; + *denominator = 1; + *cents = 0.0; + } + + return result; +} + +void lingot_config_scale_format_shift(char* char_buffer, double cents, + short int numerator, short int denominator) { + if (numerator < 0) { + sprintf(char_buffer, "%0.4lf", cents); + } else { + sprintf(char_buffer, "%hd/%hd", numerator, denominator); + } +} + +int lingot_config_scale_load_scl(LingotScale* scale, char* filename) { + FILE* fp; + int i; + char* char_buffer_pointer1; + char* nl; + const static char* delim = " \t\n"; + int result = 1; + +# define MAX_LINE_SIZE 1000 + + char char_buffer[MAX_LINE_SIZE]; + + if ((fp = fopen(filename, "r")) == NULL) { + sprintf(char_buffer, "error opening scale file %s", filename); + perror(char_buffer); + return 0; + } + + scale->base_frequency = MID_C_FREQUENCY; + + fgets(char_buffer, MAX_LINE_SIZE, fp); + if (strchr(char_buffer, '!') != char_buffer) { + fclose(fp); + return 0; + } + + fgets(char_buffer, MAX_LINE_SIZE, fp); + fgets(char_buffer, MAX_LINE_SIZE, fp); + + nl = strrchr(char_buffer, '\r'); + if (nl) + *nl = '\0'; + nl = strrchr(char_buffer, '\n'); + if (nl) + *nl = '\0'; + scale->name = strdup(char_buffer); + + fgets(char_buffer, MAX_LINE_SIZE, fp); + sscanf(char_buffer, "%hu", &scale->notes); + + fgets(char_buffer, MAX_LINE_SIZE, fp); + lingot_config_scale_allocate(scale, scale->notes); + + scale->note_name[0] = strdup("1"); + scale->offset_cents[0] = 0.0; + scale->offset_ratios[0][0] = 1; + scale->offset_ratios[1][0] = 1; // 1/1 + + for (i = 1; i < scale->notes; i++) { + + fgets(char_buffer, MAX_LINE_SIZE, fp); + + char_buffer_pointer1 = strtok(char_buffer, delim); + + int r = lingot_config_scale_parse_shift(char_buffer_pointer1, + &scale->offset_cents[i], &scale->offset_ratios[0][i], + &scale->offset_ratios[1][i]); + if (!r) { + result = 0; + } + + sprintf(char_buffer, "%d", i + 1); + scale->note_name[i] = strdup(char_buffer); + } + + fclose(fp); + +# undef MAX_LINE_SIZE + return result; +} |
