aboutsummaryrefslogtreecommitdiff
path: root/rhythm_ioi_histogram.c
diff options
context:
space:
mode:
Diffstat (limited to 'rhythm_ioi_histogram.c')
-rw-r--r--rhythm_ioi_histogram.c428
1 files changed, 428 insertions, 0 deletions
diff --git a/rhythm_ioi_histogram.c b/rhythm_ioi_histogram.c
new file mode 100644
index 0000000..8d9dc76
--- /dev/null
+++ b/rhythm_ioi_histogram.c
@@ -0,0 +1,428 @@
+/* Rhythm estimation in real time
+ Copyright (C) 2000 Jarno Seppänen and Piotr Majdak
+ $Id: rhythm_ioi_histogram.c,v 1.1 2002-11-19 11:39:55 ggeiger Exp $
+
+ This file is part of rhythm_estimator.
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "rhythm_ioi_histogram.h"
+
+
+Rhythm_Ioi_Histogram*
+rhythm_ioi_histogram_new (void)
+{
+ Rhythm_Ioi_Histogram* ge = NULL;
+
+#if RHYTHM_ESTIMATOR_DEBUG_TEXT
+ fputs ("rhythm_ioi_histogram_new\n", stderr);
+#endif
+
+ /* Allocate memory for our data structure */
+ ge = calloc (1, sizeof (Rhythm_Ioi_Histogram));
+ if (ge == NULL)
+ {
+ printf ("Not enough memory.");
+ assert (0);
+ }
+
+ /* Initialize data members */
+ ge->ioi_resolution = RHYTHM_ESTIMATOR_DEFAULT_IOI_RESOLUTION;
+ ge->min_quantum = RHYTHM_ESTIMATOR_DEFAULT_MIN_QUANTUM;
+ ge->max_quantum = RHYTHM_ESTIMATOR_DEFAULT_MAX_QUANTUM;
+ ge->hist_cycles = RHYTHM_IOI_HISTOGRAM_DEFAULT_HIST_CYCLES;
+ ge->hist_half_life = RHYTHM_IOI_HISTOGRAM_DEFAULT_HIST_HALF_LIFE;
+
+ /* Initialize onset FIFO */
+ ge->fifo_length = RHYTHM_IOI_HISTOGRAM_IOI_FIFO_LENGTH;
+ ge->fifo_buffer = calloc (ge->fifo_length, sizeof (float));
+ if (ge->fifo_buffer == NULL)
+ {
+ printf("Not enough memory.");
+ assert (0);
+ }
+
+ /* Compute internal "helper" variables */
+ assert (ge->ioi_resolution != 0);
+ ge->hist_length = (unsigned)(ge->hist_cycles * ge->max_quantum
+ / ge->ioi_resolution);
+
+ /* Initialize filling IOI histogram */
+ ge->fill_ioi_histogram = calloc (ge->hist_length, sizeof (float));
+ if (ge->fill_ioi_histogram == NULL)
+ {
+ printf("Not enough memory.");
+ assert (0);
+ }
+
+ /* Initialize main IOI histogram */
+ ge->main_ioi_histogram = calloc (ge->hist_length, sizeof (float));
+ if (ge->main_ioi_histogram == NULL)
+ {
+ printf("Not enough memory.");
+ assert (0);
+ }
+
+ return ge;
+}
+
+void
+rhythm_ioi_histogram_delete (Rhythm_Ioi_Histogram* rhythm_ioi_histogram)
+{
+#if RHYTHM_ESTIMATOR_DEBUG_TEXT
+ fputs ("rhythm_ioi_histogram_delete\n", stderr);
+#endif
+
+ if (rhythm_ioi_histogram->main_ioi_histogram != NULL)
+ {
+ free (rhythm_ioi_histogram->main_ioi_histogram);
+ rhythm_ioi_histogram->main_ioi_histogram = NULL;
+ }
+
+ if (rhythm_ioi_histogram->fill_ioi_histogram != NULL)
+ {
+ free (rhythm_ioi_histogram->fill_ioi_histogram);
+ rhythm_ioi_histogram->fill_ioi_histogram = NULL;
+ }
+
+ if (rhythm_ioi_histogram->fifo_buffer != NULL)
+ {
+ free (rhythm_ioi_histogram->fifo_buffer);
+ rhythm_ioi_histogram->fifo_buffer = NULL;
+ }
+ rhythm_ioi_histogram->fifo_length = 0;
+ rhythm_ioi_histogram->fifo_num_onsets = 0;
+
+ if (rhythm_ioi_histogram != NULL)
+ {
+ free (rhythm_ioi_histogram);
+ rhythm_ioi_histogram = NULL;
+ }
+}
+
+void
+rhythm_ioi_histogram_initialize (Rhythm_Ioi_Histogram* ge)
+{
+ unsigned i = 0;
+
+ /* precondition(s) */
+ assert (ge != NULL);
+
+#if RHYTHM_ESTIMATOR_DEBUG_TEXT
+ fputs ("rhythm_ioi_histogram_initialize\n", stderr);
+#endif
+
+ /* Clear FIFO */
+ ge->fifo_num_onsets = 0;
+ ge->fifo_current_index = 0;
+
+ /* Clear IOI histograms */
+ for (i = 0; i < ge->hist_length; i++)
+ {
+ ge->fill_ioi_histogram[i] = 0.0;
+ ge->main_ioi_histogram[i] = 0.0;
+ }
+
+ /* Initialize histogram update time variable */
+ ge->main_histogram_update_time = 0;
+}
+
+void
+rhythm_ioi_histogram_finish (Rhythm_Ioi_Histogram* rhythm_ioi_histogram)
+{
+ /* precondition(s) */
+ assert (rhythm_ioi_histogram != NULL);
+
+#if RHYTHM_ESTIMATOR_DEBUG_TEXT
+ fputs ("rhythm_ioi_histogram_finish\n", stderr);
+#endif
+}
+
+int
+rhythm_ioi_histogram_onset_event (Rhythm_Ioi_Histogram* ge, double time)
+{
+ unsigned i = 0;
+
+ /* precondition(s) */
+ assert (ge != NULL);
+
+#if RHYTHM_ESTIMATOR_DEBUG_TEXT
+ fprintf (stderr, "rhythm_ioi_histogram_onset_event: time %f ms\n", time);
+#endif
+
+ /* Compute inter-onset interval (IOI) histogram fill function */
+ for (i = 0; i < ge->fifo_num_onsets; i++)
+ {
+ double ioi;
+ unsigned ioi_index;
+
+ /* First, compute the exact IOI */
+
+ /* (a) When the FIFO is not full, the onset values are
+ positioned in FIFO begin from 0 to num_onsets - 1
+ (b) When the FIFO is full, it doesn't matter in
+ which order the onsets are inspected, therefore
+ we loop from 0 to num_onsets - 1 (end of FIFO) */
+ ioi = time - ge->fifo_buffer[i];
+
+ /* Then, the exact "continuous" IOI is discretized (quantized) */
+ ioi_index = (unsigned)rint (ioi / ge->ioi_resolution);
+
+ /* Next, increment the proper "fill" histogram bin by one */
+ if (ioi_index < ge->hist_length)
+ {
+ ge->fill_ioi_histogram[ioi_index]++;
+ /* Set a flag for the periodic_event function */
+ ge->fill_histogram_changed = 1;
+ }
+ }
+
+ /* Shift onset FIFO and store new onset */
+ ge->fifo_buffer[ge->fifo_current_index] = time;
+ ge->fifo_current_index = (ge->fifo_current_index + 1) % ge->fifo_length;
+ if (ge->fifo_num_onsets < ge->fifo_length)
+ {
+ ge->fifo_num_onsets++;
+ }
+ if(ge->fill_histogram_changed)
+ {
+ rhythm_ioi_histogram_periodic_event(ge, time);
+ ge->fill_histogram_changed = 0;
+ /* Update PD-array */
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void
+rhythm_ioi_histogram_periodic_event (Rhythm_Ioi_Histogram* ge, double time)
+{
+ unsigned i = 0;
+ double time_passed = 0.0;
+
+ /* precondition(s) */
+ assert (ge != NULL);
+
+#if RHYTHM_ESTIMATOR_DEBUG_TEXT
+ fprintf (stderr, "rhythm_ioi_histogram_periodic_event: time %f ms\n", time);
+#endif
+
+ /* Get the amount of time since last histogram update */
+ if (ge->main_histogram_update_time == 0)
+ {
+ /* Have the new IOI's get through to the histogram */
+ time_passed = 1.0e10;
+ }
+ else
+ {
+ /* Compute time since last update */
+ time_passed = time - ge->main_histogram_update_time;
+ }
+
+ /* Save time for next event */
+ ge->main_histogram_update_time = time;
+
+ /* Accumulate the main IOI histogram */
+ rhythm_ioi_histogram_update_ioi_histogram (ge, time_passed);
+
+#if RHYTHM_ESTIMATOR_DEBUG_TEXT
+ /* Dump main IOI histogram for debugging */
+ printf ("HIST: ");
+ for (i = 0; i < ge->hist_length; i++)
+ {
+ printf ("%f ", (double)(ge->main_ioi_histogram[i]));
+ }
+ printf ("\n.\n");
+#endif
+
+ /* Clear fill IOI histogram */
+ for (i = 0; i < ge->hist_length; i++)
+ {
+ ge->fill_ioi_histogram[i] = 0;
+ }
+}
+
+static void
+rhythm_ioi_histogram_update_ioi_histogram (Rhythm_Ioi_Histogram* ge, double time_passed)
+{
+ unsigned i = 0;
+ double coeff_old = 0.0;
+ double coeff_new = 0.0;
+
+ /* Compute the coefficients needed for update */
+ coeff_old = pow (0.5, time_passed / ge->hist_half_life);
+ /*coeff_new = (1 - coeff_old) / coeff_old;*/
+ coeff_new = 1 - coeff_old;
+
+#if RHYTHM_ESTIMATOR_DEBUG_TEXT
+ printf ("time_passed=%.2f, coeff_old=%.2f, coeff_new=%.2f\n",
+ time_passed, coeff_old, coeff_new);
+#endif
+
+ /* Update main_ioi_histogram now */
+ for (i = 0; i < ge->hist_length; i++)
+ {
+ ge->main_ioi_histogram[i] =
+ coeff_old * ge->main_ioi_histogram[i]
+ + coeff_new * ge->fill_ioi_histogram[i];
+ }
+}
+
+
+float
+rhythm_ioi_histogram_get_ioi_resolution (Rhythm_Ioi_Histogram* rhythm_ioi_histogram)
+{
+ /* precondition(s) */
+ assert (rhythm_ioi_histogram != NULL);
+
+ /* get the parameter */
+ return rhythm_ioi_histogram->ioi_resolution;
+}
+
+float
+rhythm_ioi_histogram_get_min_quantum (Rhythm_Ioi_Histogram* rhythm_ioi_histogram)
+{
+ /* precondition(s) */
+ assert (rhythm_ioi_histogram != NULL);
+
+ /* get the parameter */
+ return rhythm_ioi_histogram->min_quantum;
+}
+
+float
+rhythm_ioi_histogram_get_max_quantum (Rhythm_Ioi_Histogram* rhythm_ioi_histogram)
+{
+ /* precondition(s) */
+ assert (rhythm_ioi_histogram != NULL);
+
+ /* get the parameter */
+ return rhythm_ioi_histogram->max_quantum;
+}
+
+float
+rhythm_ioi_histogram_get_hist_cycles (Rhythm_Ioi_Histogram* rhythm_ioi_histogram)
+{
+ /* precondition(s) */
+ assert (rhythm_ioi_histogram != NULL);
+
+ /* get the parameter */
+ return rhythm_ioi_histogram->hist_cycles;
+}
+
+float
+rhythm_ioi_histogram_get_hist_half_life (Rhythm_Ioi_Histogram* rhythm_ioi_histogram)
+{
+ /* precondition(s) */
+ assert (rhythm_ioi_histogram != NULL);
+
+ /* get the parameter */
+ return rhythm_ioi_histogram->hist_half_life;
+}
+
+void
+rhythm_ioi_histogram_set_ioi_resolution (Rhythm_Ioi_Histogram* rhythm_ioi_histogram, float v)
+{
+ /* precondition(s) */
+ assert (rhythm_ioi_histogram != NULL);
+
+ /* sanity check(s) */
+ if (v < 1)
+ {
+ fprintf (stderr, "ERROR rhythm_ioi_histogram: ioi_resolution must not be less than 1 ms\n");
+ v = 1;
+ }
+
+ /* set the parameter */
+ rhythm_ioi_histogram->ioi_resolution = v;
+}
+
+void
+rhythm_ioi_histogram_set_min_quantum (Rhythm_Ioi_Histogram* rhythm_ioi_histogram, float v)
+{
+ /* precondition(s) */
+ assert (rhythm_ioi_histogram != NULL);
+
+ /* sanity check(s) */
+ if (v < 1)
+ {
+ fprintf (stderr, "ERROR rhythm_ioi_histogram: min_quantum must not be less than 1 ms\n");
+ v = 1;
+ }
+
+ /* set the parameter */
+ rhythm_ioi_histogram->min_quantum = v;
+}
+
+void
+rhythm_ioi_histogram_set_max_quantum (Rhythm_Ioi_Histogram* rhythm_ioi_histogram, float v)
+{
+ /* precondition(s) */
+ assert (rhythm_ioi_histogram != NULL);
+
+ /* sanity check(s) */
+ if (v < 1)
+ {
+ fprintf (stderr, "ERROR rhythm_ioi_histogram: max_quantum must not be less than 1 ms\n");
+ v = 1;
+ }
+
+ /* set the parameter */
+ rhythm_ioi_histogram->max_quantum = v;
+}
+
+void
+rhythm_ioi_histogram_set_hist_cycles (Rhythm_Ioi_Histogram* rhythm_ioi_histogram, float v)
+{
+ /* precondition(s) */
+ assert (rhythm_ioi_histogram != NULL);
+
+ /* sanity check(s) */
+ if (v <= 0)
+ {
+ fprintf (stderr, "ERROR rhythm_ioi_histogram: hist_cycles must be positive\n");
+ v = 1;
+ }
+
+ /* set the parameter */
+ rhythm_ioi_histogram->hist_cycles = v;
+}
+
+void
+rhythm_ioi_histogram_set_hist_half_life (Rhythm_Ioi_Histogram* rhythm_ioi_histogram, float v)
+{
+ /* precondition(s) */
+ assert (rhythm_ioi_histogram != NULL);
+
+ /* sanity check(s) */
+ if (v <= 0)
+ {
+ fprintf (stderr, "ERROR rhythm_ioi_histogram: hist_half_life must be positive\n");
+ v = 1;
+ }
+
+ /* set the parameter */
+ rhythm_ioi_histogram->hist_half_life = v;
+}
+
+
+/* EOF */