Subversion Repositories DIN Is Noise

Rev

Rev 2302 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
* play.cc
* DIN Is Noise is copyright (c) 2006-2025 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/


#include "audio.h"
#include "play.h"
#include "multi_curve.h"
#include <string.h>

void play::init () {
  sol = 0;
  x = 0.0f;
  dx = 0.0f;
  vol = 0.0f;
  pdx = pvol = 0;
  alloc ();
  pdx [0] = 0.0f; pdx [n_1] = 1.0f;
  pvol [0] = 0.0f; pvol [n_1] = 1.0f;
}

void play::alloc () {
  n = aout.samples_per_channel;
  n_1 = n - 1;
  da = 1.0f / n_1;
  if (pdx) delete [] pdx;
  if (pvol) delete [] pvol;
  pdx = new float [n];
  pvol = new float [n];
  int sz = n * sizeof (float);
  memset (pdx, 0, sz);
  memset (pvol, 0, sz);
}

void play::realloc () {
  alloc ();
  fill_pitch (dx);
  fill_volume (vol);
}

play::play (solver *w) {
  init ();
  set_wave (w);
}

play::play () {
  init ();
}

play::play (const play& p) {
  sol = p.sol;
  x = p.x;
  dx = p.dx;
  vol = p.vol;
  n = p.n;
  n_1 = p.n_1;
  da = p.da;
  pdx = new float [n];
  pvol = new float [n];
  for (int i = 0; i < n; ++i) {
    pdx [i] = p.pdx [i];
    pvol [i] = p.pvol [i];
  }
}

play::~play () {
  if (pdx) delete[] pdx;
  if (pvol) delete[] pvol;
}

void play::fill_pitch (float xd) {
  for (int i = 0; i < n; ++i) pdx[i] = xd;
  dx = xd;
}

void play::fill_volume (float v) {
  for (int i = 0; i < n; ++i) pvol[i] = v;
  vol = v;
}

void play::interpolate_buffer (float* buf, float s, float e) {
  float a = 0;
  float es = e - s;
  for (int i = 0; i < n; ++i) {
    buf[i] = s + a * es;
    a += da;
  }
}

void play::set_interpolated_volume (float v) {
  interpolate_buffer (pvol, vol, v);
  vol = v;
}

void play::set_interpolated_pitch (float xd) {
  interpolate_buffer (pdx, dx, xd);
  dx = xd;
}

void play::set_interpolated_pitch (float xd, int check) {
  if ((pdx[0] == pdx[n_1]) && (pdx[0] == xd)) return; // pitch is same
  else
    if (xd == dx)
      for (int i = 0; i < n; ++i) pdx[i] = dx; // same as last pitch so just fill ie no interpolation needed
    else
      set_interpolated_pitch (xd);
}

void play::set_interpolated_volume (float v, int check) {
  if ((pvol[0]==pvol[n_1]) && (pvol[0]==v)) return; // volume is same
  else
    if (v == vol)
      for (int i = 0; i < n; ++i) pvol[i] = v; // same as last volume so just fill ie no interpolation needed
    else
      set_interpolated_volume (v);
}

void play::gen_wav_and_mix (float* wav, int n) {
  (*sol) (x, pdx, n, wav);
  if (mixer.active) {
    mixer.gen_mix (aout.mix, n);
    mixer.do_mix (wav, aout.mix, aout.mixa, n);
  }
}

void play::master (float* L, float* R, float* wav, int n, float* vola)  { // master with volume array
  gen_wav_and_mix (wav, n); // mix waveforms
  operator() (L, n, wav, vola); // multiply volumes
  memcpy (R, L, aout.samples_channel_size); // copy to R
}

void play::master (float* L, float* R, float* wav, int n, float vol)  { // master with volume
  gen_wav_and_mix (wav, n); // mix waveforms
  operator() (L, n, wav, vol); // apply volume
  memcpy (R, L, aout.samples_channel_size); // copy to R
}


void play::master (float* L, float* wav, int n, float vol)  { // master with volume
  gen_wav_and_mix (wav, n); // mix waveforms
  operator() (L, n, wav, vol); // apply volume
}


void play::master (float* L, float* wav, int n, float* vola)  { // master with volume array
  gen_wav_and_mix (wav, n); // mix waveforms
  operator() (L, n, wav, vola); // apply volume
}

void play::gen_wav_fm (solver& _sol, float& _x, float* wav, float* fm, int n) {
  // generate waveform samples with FM
  _sol (_x, pdx, n, fm, wav);
}

void play::gen_wav_am (float* out, float* wav, float* am, int n) { // apply AM to waveform samples
  for (int i = 0; i < n; ++i) out[i] = ((pvol[i] + am[i]) * wav[i]);
}

void play::gen_wav_fm_am_mix (float* out, int n) { // generate waveform samples, apply AM and FM and mix (if present)
  gen_wav_fm (*sol, x, aout.result, aout.fms, n);
  gen_wav_am (out, aout.result, aout.ams, n);
  if (mixer.active) {
    mixer.gen_fm (aout.result, n, aout.fms);
    gen_wav_am (aout.mix, aout.result, aout.ams, n);
    mixer.do_mix (out, aout.mix, aout.mixa, n);
  }
}

void play::gen_wav_mix (float* out, float* vola, int n) {
  gen_wav_and_mix (aout.result, n);
  operator() (out, n, aout.result, vola);
}

void play::gen_wav_mix (float* out, float vol, int n) {
  gen_wav_and_mix (aout.result, n);
  operator() (out, n, aout.result, vol);
}

void play::set_mix (multi_curve& crv, const std::string& nam) {
  mixer.setup (crv, x, dx);
  mixer.name = nam;
}