<commit_before>/* BSE - Bedevilled Sound Engine
 * Copyright (C) 2003 <NAME>
 *
 * This library 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 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 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 "bseprobe.gen-idl.h"
#include "bseengine.h"
#include "gslcommon.h" /* for gsl_tick_stamp() */
#include "gslfft.h"
#include <stdexcept>
#include <queue>
using namespace std;
using namespace Sfi;

namespace { // Anon
using namespace Bse;

static const guint PROBE_QUEUE_LENGTH = 3;
static guint signal_probes = 0;

class SourceProbes {
  BseSource          *source;
  guint               n_channels;
  vector<ProbeHandle> channel_probes;
  vector<guint8>      range_ages, energie_ages, samples_ages, fft_ages, channel_ages;
  guint               bsize_fifo[PROBE_QUEUE_LENGTH], bsize_offset;
  SfiRing            *omodules;
  guint               queued_jobs;
  guint               idle_handler_id;
  void
  resize_ochannels (guint n_ochannels)
  {
    n_channels = n_ochannels;
    range_ages.resize (n_channels, 0);
    energie_ages.resize (n_channels, 0);
    samples_ages.resize (n_channels, 0);
    fft_ages.resize (n_channels, 0);
    channel_ages.resize (n_channels, 0);
    Probe zprobe;
    zprobe.probe_features = ProbeFeatures();
    channel_probes.resize (n_channels, zprobe);
  }
public:
  SourceProbes (BseSource *src) :
    source (src), n_channels (0), omodules (NULL)
  {
    queued_jobs = 0;
    idle_handler_id = 0;
    resize_ochannels (BSE_SOURCE_N_OCHANNELS (src));
    memset (bsize_fifo, 0, sizeof (bsize_fifo));
    bsize_offset = 0;
  }
  ~SourceProbes ()
  {
    g_assert (queued_jobs == 0);
  }
  void
  reset_omodules ()
  {
    sfi_ring_free (omodules);
    omodules = NULL;
  }
private:
  SfiRing*
  get_omodules ()
  {
    if (!omodules)
      {
        omodules = bse_source_list_omodules (source);
        /* remove dupes */
        omodules = sfi_ring_sort (omodules, sfi_pointer_cmp, NULL);
        omodules = sfi_ring_uniq (omodules, sfi_pointer_cmp, NULL);
      }
    return omodules;
  }
  struct ProbeData {
    BseSource *source;
    guint      n_modules;
    guint      n_pending;
    ProbeSeq   pseq;
    ProbeData (const SourceProbes &probes)
    {
      source = probes.source;
      for (guint i = 0; i < BSE_SOURCE_N_OCHANNELS (source); i++)
        if (probes.channel_ages[i])
          {
            Probe probe;
            probe.channel_id = i;
            probe.max = SFI_MINREAL;
            probe.min = SFI_MAXREAL;
            probe.energie = -999;
            ProbeFeatures features;
            features.probe_range = probes.range_ages[i] > 0;
            features.probe_energie = probes.energie_ages[i] > 0;
            features.probe_samples = probes.samples_ages[i] > 0;
            features.probe_fft = probes.fft_ages[i] > 0;
            probe.probe_features = features;
            pseq += probe;
          }
    }
  };
  void
  fill_probe (Probe  &probe,
              guint   n_values,
              gfloat *values,
              bool    need_summing)
  {
    if (probe.probe_features->probe_range || probe.probe_features->probe_energie)
      {
        gdouble accu = 0;
        for (gfloat *v = values; v < values + n_values; v++)
          {
            if (G_UNLIKELY (*v < probe.min))
              probe.min = *v;
            if (G_UNLIKELY (*v > probe.max))
              probe.max = *v;
            accu += *v * *v;
          }
        probe.energie = accu > 0 ? 10 * log10 (accu / n_values) : -999;
      }
    SfiFBlock *fblock = probe.sample_data.fblock();
    if (need_summing && fblock)
      {
        gfloat *v = values;
        for (FBlock::iterator it = probe.sample_data.begin(); it != probe.sample_data.end(); it++)
          *it += *v++;
      }
  }
  /* returns a blackman window: x is supposed to be in the interval [0..1] */
  inline double
  blackman_window (double x)
  {
    if (x < 0)
      return 0;
    if (x > 1)
      return 0;
    return 0.42 - 0.5 * cos (PI * x * 2) + 0.08 * cos (4 * PI * x);
  }
  void
  handle_probes (ProbeData &pdata,
                 guint64    tick_stamp,
                 guint      n_values,
                 gfloat   **oblocks) /* [ENGINE_NODE_N_OSTREAMS()] */
  {
    if (pdata.n_pending == pdata.n_modules - 1) /* setup fblocks from first module */
      for (ProbeSeq::iterator it = pdata.pseq.begin(); it != pdata.pseq.end(); it++)
        {
          Probe &probe = **it;
          gfloat *block = oblocks[probe.channel_id];
          if (probe.probe_features->probe_samples || probe.probe_features->probe_fft)
            {
              probe.sample_data.take (sfi_fblock_new_foreign (n_values, block, g_free));
              oblocks[probe.channel_id] = NULL; /* steal from engine */
              fill_probe (probe, n_values, block, FALSE);
            }
          else
            fill_probe (probe, n_values, block, FALSE);
        }
    else
      for (ProbeSeq::iterator it = pdata.pseq.begin(); it != pdata.pseq.end(); it++)
        fill_probe (**it, n_values, oblocks[(*it)->channel_id], TRUE);
    if (!pdata.n_pending)       /* last module */
      {
        /* min/max fixup */
        if (!n_values)
          for (ProbeSeq::iterator it = pdata.pseq.begin(); it != pdata.pseq.end(); it++)
            {
              Probe &probe = **it;
              if (probe.probe_features->probe_range && probe.max < probe.min)
                probe.min = probe.max = 0;
            }
        /* complete fft */
        for (ProbeSeq::iterator it = pdata.pseq.begin(); it != pdata.pseq.end(); it++)
          {
            Probe &probe = **it;
            if (probe.probe_features->probe_fft)
              {
                guint fft_size = probe.sample_data.length();
                if (fft_size)
                  {
                    fft_size = 1 << (g_bit_storage (num) - 1);
                    fft_size = CLAMP (fft_size, 2, 65536);
                    probe.fft_data.resize (fft_size);
                    /* perform fft */
                    double *rv = g_new (double, fft_size * 2), *cv = rv + fft_size; // FIXME: optimize
                    gfloat *fvalues = probe.sample_data.fblock()->values;
                    double reci_fft_size = 1.0 / (fft_size - 1);
                    guint i = fft_size;
                    while (i--) /* convert to double */
                      rv[i] = fvalues[i] * blackman_window (i * reci_fft_size);<commit_msg>fix typo<commit_after>/* BSE - Bedevilled Sound Engine
 * Copyright (C) 2003 <NAME>
 *
 * This library 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 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 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 "bseprobe.gen-idl.h"
#include "bseengine.h"
#include "gslcommon.h" /* for gsl_tick_stamp() */
#include "gslfft.h"
#include <stdexcept>
#include <queue>
using namespace std;
using namespace Sfi;

namespace { // Anon
using namespace Bse;

static const guint PROBE_QUEUE_LENGTH = 3;
static guint signal_probes = 0;

class SourceProbes {
  BseSource          *source;
  guint               n_channels;
  vector<ProbeHandle> channel_probes;
  vector<guint8>      range_ages, energie_ages, samples_ages, fft_ages, channel_ages;
  guint               bsize_fifo[PROBE_QUEUE_LENGTH], bsize_offset;
  SfiRing            *omodules;
  guint               queued_jobs;
  guint               idle_handler_id;
  void
  resize_ochannels (guint n_ochannels)
  {
    n_channels = n_ochannels;
    range_ages.resize (n_channels, 0);
    energie_ages.resize (n_channels, 0);
    samples_ages.resize (n_channels, 0);
    fft_ages.resize (n_channels, 0);
    channel_ages.resize (n_channels, 0);
    Probe zprobe;
    zprobe.probe_features = ProbeFeatures();
    channel_probes.resize (n_channels, zprobe);
  }
public:
  SourceProbes (BseSource *src) :
    source (src), n_channels (0), omodules (NULL)
  {
    queued_jobs = 0;
    idle_handler_id = 0;
    resize_ochannels (BSE_SOURCE_N_OCHANNELS (src));
    memset (bsize_fifo, 0, sizeof (bsize_fifo));
    bsize_offset = 0;
  }
  ~SourceProbes ()
  {
    g_assert (queued_jobs == 0);
  }
  void
  reset_omodules ()
  {
    sfi_ring_free (omodules);
    omodules = NULL;
  }
private:
  SfiRing*
  get_omodules ()
  {
    if (!omodules)
      {
        omodules = bse_source_list_omodules (source);
        /* remove dupes */
        omodules = sfi_ring_sort (omodules, sfi_pointer_cmp, NULL);
        omodules = sfi_ring_uniq (omodules, sfi_pointer_cmp, NULL);
      }
    return omodules;
  }
  struct ProbeData {
    BseSource *source;
    guint      n_modules;
    guint      n_pending;
    ProbeSeq   pseq;
    ProbeData (const SourceProbes &probes)
    {
      source = probes.source;
      for (guint i = 0; i < BSE_SOURCE_N_OCHANNELS (source); i++)
        if (probes.channel_ages[i])
          {
            Probe probe;
            probe.channel_id = i;
            probe.max = SFI_MINREAL;
            probe.min = SFI_MAXREAL;
            probe.energie = -999;
            ProbeFeatures features;
            features.probe_range = probes.range_ages[i] > 0;
            features.probe_energie = probes.energie_ages[i] > 0;
            features.probe_samples = probes.samples_ages[i] > 0;
            features.probe_fft = probes.fft_ages[i] > 0;
            probe.probe_features = features;
            pseq += probe;
          }
    }
  };
  void
  fill_probe (Probe  &probe,
              guint   n_values,
              gfloat *values,
              bool    need_summing)
  {
    if (probe.probe_features->probe_range || probe.probe_features->probe_energie)
      {
        gdouble accu = 0;
        for (gfloat *v = values; v < values + n_values; v++)
          {
            if (G_UNLIKELY (*v < probe.min))
              probe.min = *v;
            if (G_UNLIKELY (*v > probe.max))
              probe.max = *v;
            accu += *v * *v;
          }
        probe.energie = accu > 0 ? 10 * log10 (accu / n_values) : -999;
      }
    SfiFBlock *fblock = probe.sample_data.fblock();
    if (need_summing && fblock)
      {
        gfloat *v = values;
        for (FBlock::iterator it = probe.sample_data.begin(); it != probe.sample_data.end(); it++)
          *it += *v++;
      }
  }
  /* returns a blackman window: x is supposed to be in the interval [0..1] */
  inline double
  blackman_window (double x)
  {
    if (x < 0)
      return 0;
    if (x > 1)
      return 0;
    return 0.42 - 0.5 * cos (PI * x * 2) + 0.08 * cos (4 * PI * x);
  }
  void
  handle_probes (ProbeData &pdata,
                 guint64    tick_stamp,
                 guint      n_values,
                 gfloat   **oblocks) /* [ENGINE_NODE_N_OSTREAMS()] */
  {
    if (pdata.n_pending == pdata.n_modules - 1) /* setup fblocks from first module */
      for (ProbeSeq::iterator it = pdata.pseq.begin(); it != pdata.pseq.end(); it++)
        {
          Probe &probe = **it;
          gfloat *block = oblocks[probe.channel_id];
          if (probe.probe_features->probe_samples || probe.probe_features->probe_fft)
            {
              probe.sample_data.take (sfi_fblock_new_foreign (n_values, block, g_free));
              oblocks[probe.channel_id] = NULL; /* steal from engine */
              fill_probe (probe, n_values, block, FALSE);
            }
          else
            fill_probe (probe, n_values, block, FALSE);
        }
    else
      for (ProbeSeq::iterator it = pdata.pseq.begin(); it != pdata.pseq.end(); it++)
        fill_probe (**it, n_values, oblocks[(*it)->channel_id], TRUE);
    if (!pdata.n_pending)       /* last module */
      {
        /* min/max fixup */
        if (!n_values)
          for (ProbeSeq::iterator it = pdata.pseq.begin(); it != pdata.pseq.end(); it++)
            {
              Probe &probe = **it;
              if (probe.probe_features->probe_range && probe.max < probe.min)
                probe.min = probe.max = 0;
            }
        /* complete fft */
        for (ProbeSeq::iterator it = pdata.pseq.begin(); it != pdata.pseq.end(); it++)
          {
            Probe &probe = **it;
            if (probe.probe_features->probe_fft)
              {
                guint fft_size = probe.sample_data.length();
                if (fft_size)
                  {
                    fft_size = 1 << (g_bit_storage (fft_size) - 1);
                    fft_size = MIN (fft_size, 65536);
                    probe.fft_data.resize (fft_size);
                    /* perform fft */
                    double *rv = g_new (double, fft_size * 2), *cv = rv + fft_size; // FIXME: optimize
                    gfloat *fvalues = probe.sample_data.fblock()->values;
                    double reci_fft_size = 1.0 / (fft_size - 1);
                    guint i = fft_size;
                    while (i--) /* convert to double */
                      rv[i] = fvalues[i] * blackman_window (i * reci_fft_size);
{'fraction_non_alphanumeric': 0.11200057179615468, 'fraction_numerical': 0.011650346651418769, 'mean_word_length': 2.008385293485272, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6224186', 'n_tokens_mistral': 4737, 'n_tokens_neox': 4548, 'n_words': 1163}