refactor scale handling into temperament.c temperaments
authorJari Tenhunen <jari.tenhunen@iki.fi>
Sat, 27 Mar 2010 21:34:05 +0000 (21:34 +0000)
committerJari Tenhunen <jari.tenhunen@iki.fi>
Sat, 27 Mar 2010 22:06:31 +0000 (22:06 +0000)
src/Makefile.am
src/temperament.c [new file with mode: 0644]
src/temperament.h [new file with mode: 0644]
src/tuner.c

index 035a56a..21d72f9 100644 (file)
@@ -23,7 +23,7 @@ libgsttonesrc_la_LIBADD = $(GSTPB_BASE_LIBS) $(GST_BASE_LIBS) \
 libgsttonesrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 
 # headers we need but don't want installed
-noinst_HEADERS = gstpitch.h gsttonesrc.h kiss_fft.h _kiss_fft_guts.h settings.h
+noinst_HEADERS = gstpitch.h gsttonesrc.h kiss_fft.h _kiss_fft_guts.h settings.h temperament.h
 EXTRA_DIST = tuner26.png  tuner40.png  tuner64.png
 
 if HAVE_GTK
@@ -38,7 +38,7 @@ endif
 #demo_tuner_CFLAGS  = $(GST_CFLAGS) $(GTK_CFLAGS) 
 #demo_tuner_LDFLAGS = $(GST_LIBS) $(GTK_LIBS)
 
-tuner_SOURCES = tuner.c settings.c
+tuner_SOURCES = tuner.c settings.c temperament.c
 tuner_DEPENDENCIES = $(top_builddir)/src/libgstpitch.la $(top_builddir)/src/libgsttonesrc.la
 tuner_CFLAGS  = $(GST_CFLAGS) $(GTK_CFLAGS) $(MAEMO_CFLAGS) $(GCONF_CFLAGS) -D_GNU_SOURCE
 tuner_LDADD = $(GST_LIBS) $(GTK_LIBS) $(MAEMO_LIBS) $(GCONF_LIBS) $(top_builddir)/src/libgstpitch.la $(top_builddir)/src/libgsttonesrc.la
diff --git a/src/temperament.c b/src/temperament.c
new file mode 100644 (file)
index 0000000..e3d2777
--- /dev/null
@@ -0,0 +1,174 @@
+/* vim: set sts=2 sw=2 et: */
+/* 
+ * Copyright (C) 2010 Jari Tenhunen <jari.tenhunen@iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include "temperament.h"
+
+#define CENT (1.0005777895f) /* 1/100th of a half-tone */
+#define LOG_CENT (0.00057762265046662109f) /* ln (CENT) */
+#define MAGIC (1.059463094359f) /* 2^(1/2) */
+
+static Note scale[] = {
+  {"C0", 16.35},
+  {"C#0/Db0", 17.32},
+  {"D0", 18.35},
+  {"D#0/Eb0", 19.45},
+  {"E0", 20.60},
+  {"F0", 21.83},
+  {"F#0/Gb0", 23.12},
+  {"G0", 24.50},
+  {"G#0/Ab0", 25.96},
+  {"A0", 27.50},
+  {"A#0/Bb0", 29.14},
+  {"B0", 30.87},
+  {"C1", 32.70},
+  {"C#1/Db1", 34.65},
+  {"D1", 36.71},
+  {"D#1/Eb1", 38.89},
+  {"E1", 41.20},
+  {"F1", 43.65},
+  {"F#1/Gb1", 46.25},
+  {"G1", 49.00},
+  {"G#1/Ab1", 51.91},
+  {"A1", 55.00},
+  {"A#1/Bb1", 58.27},
+  {"B1", 61.74},
+  {"C2", 65.41},
+  {"C#2/Db2", 69.30},
+  {"D2", 73.42},
+  {"D#2/Eb2", 77.78},
+  {"E2", 82.41},
+  {"F2", 87.31},
+  {"F#2/Gb2", 92.50},
+  {"G2", 98.00},
+  {"G#2/Ab2", 103.83},
+  {"A2", 110.00},
+  {"A#2/Bb2", 116.54},
+  {"B2", 123.47},
+  {"C3", 130.81},
+  {"C#3/Db3", 138.59},
+  {"D3", 146.83},
+  {"D#3/Eb3", 155.56},
+  {"E3", 164.81},
+  {"F3", 174.61},
+  {"F#3/Gb3", 185.00},
+  {"G3", 196.00},
+  {"G#3/Ab3", 207.65},
+  {"A3", 220.00},
+  {"A#3/Bb3", 233.08},
+  {"B3", 246.94},
+  {"C4", 261.63},
+  {"C#4/Db4", 277.18},
+  {"D4", 293.66},
+  {"D#4/Eb4", 311.13},
+  {"E4", 329.63},
+  {"F4", 349.23},
+  {"F#4/Gb4", 369.99},
+  {"G4", 392.00},
+  {"G#4/Ab4", 415.30},
+  {"A4", 440.00},
+  {"A#4/Bb4", 466.16},
+  {"B4", 493.88},
+  {"C5", 523.25},
+  {"C#5/Db5", 554.37},
+  {"D5", 587.33},
+  {"D#5/Eb5", 622.25},
+  {"E5", 659.26},
+  {"F5", 698.46},
+  {"F#5/Gb5", 739.99},
+  {"G5", 783.99},
+  {"G#5/Ab5", 830.61},
+  {"A5", 880.00},
+  {"A#5/Bb5", 932.33},
+  {"B5", 987.77},
+  {"C6", 1046.50},
+  {"C#6/Db6", 1108.73},
+  {"D6", 1174.66},
+  {"D#6/Eb6", 1244.51},
+  {"E6", 1318.51},
+  {"F6", 1396.91},
+  {"F#6/Gb6", 1479.98},
+  {"G6", 1567.98},
+  {"G#6/Ab6", 1661.22},
+  {"A6", 1760.00},
+  {"A#6/Bb6", 1864.66},
+  {"B6", 1975.53},
+  {"C7", 2093.00},
+  {"C#7/Db7", 2217.46},
+  {"D7", 2349.32},
+  {"D#7/Eb7", 2489.02},
+  {"E7", 2637.02},
+  {"F7", 2793.83},
+  {"F#7/Gb7", 2959.96},
+  {"G7", 3135.96},
+  {"G#7/Ab7", 3322.44},
+  {"A7", 3520.00},
+  {"A#7/Bb7", 3729.31},
+  {"B7", 3951.07},
+};
+
+void
+recalculate_scale (double a4)
+{
+  int i;
+
+  for (i = 0; i < NUM_NOTES; i++) {
+    scale[i].frequency = a4 * pow (MAGIC, i - 57);
+    /* fprintf(stdout, "%s: %.2f\n", scale[i].name, scale[i].frequency); */
+  }
+}
+
+/* translate the interval (ratio of two freqs) into cents */
+gfloat
+interval2cent (gfloat freq, gfloat note)
+{
+  //return (gfloat) (log (freq / note) / log (CENT));
+  return (gfloat) (log (freq / note) / LOG_CENT);
+}
+
+Note *
+get_nearest_note (gfloat frequency)
+{
+  gint i, j;
+  gfloat diff, min_diff;
+
+  min_diff = frequency - (scale[0].frequency - 10);
+  for (i = j = 0; i < NUM_NOTES; i++) {
+    diff = frequency - scale[i].frequency;
+    if (fabs (diff) <= fabs (min_diff)) {
+      min_diff = diff;
+      j = i;
+    } else {
+      break;
+    }
+  }
+
+  return &(scale[j]);
+}
+
+Note *
+get_scale (void)
+{
+  return scale;
+}
diff --git a/src/temperament.h b/src/temperament.h
new file mode 100644 (file)
index 0000000..eafb623
--- /dev/null
@@ -0,0 +1,42 @@
+/* vim: set sts=2 sw=2 et: */
+/*
+ * Copyright (C) 2010 Jari Tenhunen <jari.tenhunen@iki.fi>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __TEMPERAMENT_H__
+#define __TEMPERAMENT_H__
+
+#include <gtk/gtk.h>
+
+typedef struct
+{
+  const gchar *name;
+  gfloat frequency;
+} Note;
+
+enum
+{
+  NUM_NOTES = 96
+};
+
+gfloat interval2cent (gfloat freq, gfloat note);
+void recalculate_scale (double a4);
+Note * get_scale (void);
+Note * get_nearest_note (gfloat frequency);
+
+#endif /* __TEMPERAMENT_H__ */
index ec8d194..892e20a 100644 (file)
 
 #include "gstpitch.h"
 #include "settings.h"
+#include "temperament.h"
 
 #define between(x,a,b) (((x)>=(a)) && ((x)<=(b)))
 
-#define MAGIC (1.059463094359f) /* 2^(1/2) */
-#define CENT (1.0005777895f) /* 1/100th of a half-tone */
-#define LOG_CENT (0.00057762265046662109f) /* ln (CENT) */
-
 extern gboolean plugin_pitch_init (GstPlugin * plugin);
 extern gboolean plugin_tonesrc_init (GstPlugin * plugin);
 
-typedef struct
-{
-  const gchar *name;
-  gfloat frequency;
-} Note;
-
 struct app_data
 {
   GtkWidget *targetFrequency;
@@ -95,132 +86,16 @@ struct app_data
 
 typedef struct app_data AppData;
 
-enum
-{
-  NUM_NOTES = 96
-};
-
-
-
 #define NUM_LEDS (50)
 #define NUM_WKEYS (15) /* # of white keys in the piano keyboard */
 #define WKEY_WIDTH (45)
 
-static Note equal_tempered_scale[] = {
-  {"C0", 16.35},
-  {"C#0/Db0", 17.32},
-  {"D0", 18.35},
-  {"D#0/Eb0", 19.45},
-  {"E0", 20.60},
-  {"F0", 21.83},
-  {"F#0/Gb0", 23.12},
-  {"G0", 24.50},
-  {"G#0/Ab0", 25.96},
-  {"A0", 27.50},
-  {"A#0/Bb0", 29.14},
-  {"B0", 30.87},
-  {"C1", 32.70},
-  {"C#1/Db1", 34.65},
-  {"D1", 36.71},
-  {"D#1/Eb1", 38.89},
-  {"E1", 41.20},
-  {"F1", 43.65},
-  {"F#1/Gb1", 46.25},
-  {"G1", 49.00},
-  {"G#1/Ab1", 51.91},
-  {"A1", 55.00},
-  {"A#1/Bb1", 58.27},
-  {"B1", 61.74},
-  {"C2", 65.41},
-  {"C#2/Db2", 69.30},
-  {"D2", 73.42},
-  {"D#2/Eb2", 77.78},
-  {"E2", 82.41},
-  {"F2", 87.31},
-  {"F#2/Gb2", 92.50},
-  {"G2", 98.00},
-  {"G#2/Ab2", 103.83},
-  {"A2", 110.00},
-  {"A#2/Bb2", 116.54},
-  {"B2", 123.47},
-  {"C3", 130.81},
-  {"C#3/Db3", 138.59},
-  {"D3", 146.83},
-  {"D#3/Eb3", 155.56},
-  {"E3", 164.81},
-  {"F3", 174.61},
-  {"F#3/Gb3", 185.00},
-  {"G3", 196.00},
-  {"G#3/Ab3", 207.65},
-  {"A3", 220.00},
-  {"A#3/Bb3", 233.08},
-  {"B3", 246.94},
-  {"C4", 261.63},
-  {"C#4/Db4", 277.18},
-  {"D4", 293.66},
-  {"D#4/Eb4", 311.13},
-  {"E4", 329.63},
-  {"F4", 349.23},
-  {"F#4/Gb4", 369.99},
-  {"G4", 392.00},
-  {"G#4/Ab4", 415.30},
-  {"A4", 440.00},
-  {"A#4/Bb4", 466.16},
-  {"B4", 493.88},
-  {"C5", 523.25},
-  {"C#5/Db5", 554.37},
-  {"D5", 587.33},
-  {"D#5/Eb5", 622.25},
-  {"E5", 659.26},
-  {"F5", 698.46},
-  {"F#5/Gb5", 739.99},
-  {"G5", 783.99},
-  {"G#5/Ab5", 830.61},
-  {"A5", 880.00},
-  {"A#5/Bb5", 932.33},
-  {"B5", 987.77},
-  {"C6", 1046.50},
-  {"C#6/Db6", 1108.73},
-  {"D6", 1174.66},
-  {"D#6/Eb6", 1244.51},
-  {"E6", 1318.51},
-  {"F6", 1396.91},
-  {"F#6/Gb6", 1479.98},
-  {"G6", 1567.98},
-  {"G#6/Ab6", 1661.22},
-  {"A6", 1760.00},
-  {"A#6/Bb6", 1864.66},
-  {"B6", 1975.53},
-  {"C7", 2093.00},
-  {"C#7/Db7", 2217.46},
-  {"D7", 2349.32},
-  {"D#7/Eb7", 2489.02},
-  {"E7", 2637.02},
-  {"F7", 2793.83},
-  {"F#7/Gb7", 2959.96},
-  {"G7", 3135.96},
-  {"G#7/Ab7", 3322.44},
-  {"A7", 3520.00},
-  {"A#7/Bb7", 3729.31},
-  {"B7", 3951.07},
-};
-
 static GdkColor ledOnColor = { 0, 0 * 255, 180 * 255, 95 * 255 };
 static GdkColor ledOnColor2 = { 0, 180 * 255, 180 * 255, 0 * 255 };
 static GdkColor ledOffColor = { 0, 80 * 255, 80 * 255, 80 * 255 };
 static GdkColor whiteColor = { 0, 65535, 65535, 65535 };
 static GdkColor blackColor = { 0, 0, 0, 0 };
 
-static void
-recalculate_scale (double a4)
-{
-  int i;
-
-  for (i = 0; i < NUM_NOTES; i++) {
-    equal_tempered_scale[i].frequency = a4 * pow (MAGIC, i - 57);
-    /* fprintf(stdout, "%s: %.2f\n", equal_tempered_scale[i].name, equal_tempered_scale[i].frequency); */
-  }
-}
 
 static void
 calibration_changed (GObject * object, GParamSpec * pspec, gpointer user_data)
@@ -325,36 +200,18 @@ draw_leds (AppData * appdata, gint n)
   }
 }
 
-/* translate the interval (ratio of two freqs) into cents */
-gfloat
-interval2cent (gfloat freq, gfloat note)
-{
-  //return (gfloat) (log (freq / note) / log (CENT));
-  return (gfloat) (log (freq / note) / LOG_CENT);
-}
-
 /* update frequency info */
 static void
 update_frequency (AppData * appdata, gfloat frequency)
 {
   gchar *buffer;
-  gint i, j;
-  gfloat diff, min_diff;
-
-  min_diff = frequency - (equal_tempered_scale[0].frequency - 10);
-  for (i = j = 0; i < NUM_NOTES; i++) {
-    diff = frequency - equal_tempered_scale[i].frequency;
-    if (fabs (diff) <= fabs (min_diff)) {
-      min_diff = diff;
-      j = i;
-    } else {
-      break;
-    }
-  }
+  Note *nearest;
+  gfloat diff;
 
+  nearest = get_nearest_note (frequency);
   buffer =
       g_strdup_printf ("Nearest note is %s with %.2f Hz frequency",
-      equal_tempered_scale[j].name, equal_tempered_scale[j].frequency);
+      nearest->name, nearest->frequency);
   gtk_label_set_text (GTK_LABEL (appdata->targetFrequency), buffer);
   g_free (buffer);
 
@@ -363,7 +220,7 @@ update_frequency (AppData * appdata, gfloat frequency)
   g_free (buffer);
 
   /* make leds display the difference in steps of two cents */
-  diff = interval2cent (frequency, equal_tempered_scale[j].frequency);
+  diff = interval2cent (frequency, nearest->frequency);
   draw_leds (appdata, (gint) roundf (diff / 2.0));
 }
 
@@ -411,7 +268,7 @@ keynote2freq (AppData * appdata, gint x, gint y)
         found = j;
     }
     if (found) {
-      frequency = equal_tempered_scale[48 + found - 1].frequency;
+      frequency = get_scale()[48 + found - 1].frequency;
       break;
     }
   }