From 256119f46dce880391bd994b82be81d003056f7d Mon Sep 17 00:00:00 2001 From: Guenter Geiger Date: Tue, 19 Nov 2002 11:47:34 +0000 Subject: added svn path=/trunk/externals/rhythm_estimator/; revision=218 --- rhythm_ioi_histogram.c | 428 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 428 insertions(+) create mode 100644 rhythm_ioi_histogram.c (limited to 'rhythm_ioi_histogram.c') 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 +#include +#include +#include + +#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 */ -- cgit v1.2.1