summaryrefslogtreecommitdiffhomepage
path: root/src/lingot-config-scale.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lingot-config-scale.c')
-rw-r--r--src/lingot-config-scale.c255
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;
+}