diff options
author | IOhannes m zmölnig <zmoelnig@iem.at> | 2015-10-14 15:14:38 +0200 |
---|---|---|
committer | IOhannes m zmölnig <zmoelnig@iem.at> | 2015-10-14 15:14:38 +0200 |
commit | 28b7e464fd119b8c848753a1f41070422c463c41 (patch) | |
tree | 07449abdf85d8f1fd4068839b974242b429720ca /chaos/src/chaos_dsp.hpp | |
parent | 90c6018a9401e38859f733b3521c919e042322b7 (diff) | |
parent | 6932ee2d22511226378218992b0005cb01eb235e (diff) |
Merge branchesHEADsvn2git-headmaster
- abstractions/tb
- externals/tb
Diffstat (limited to 'chaos/src/chaos_dsp.hpp')
-rw-r--r-- | chaos/src/chaos_dsp.hpp | 532 |
1 files changed, 532 insertions, 0 deletions
diff --git a/chaos/src/chaos_dsp.hpp b/chaos/src/chaos_dsp.hpp new file mode 100644 index 0000000..6ca9ce4 --- /dev/null +++ b/chaos/src/chaos_dsp.hpp @@ -0,0 +1,532 @@ +// +// +// chaos~ +// Copyright (C) 2004 Tim Blechmann +// +// 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; see the file COPYING. If not, write to +// the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +#include "chaos_base.hpp" + +template <class system> +class chaos_dsp + : public flext_dsp +{ + FLEXT_HEADER(chaos_dsp, flext_dsp); + +protected: + chaos_dsp(int argc, t_atom* argv) + { + m_sr = 44100; /* assume default sampling rate */ + int size = m_system.get_num_eq(); + + m_values = new t_float[size]; + m_slopes = new t_float[size]; + m_nextvalues = new t_float[size]; + m_nextmidpts = new t_float[size]; + m_curves = new t_float[size]; + + /* create inlets and zero arrays*/ + for (int i = 0; i != size; ++i) + { + AddOutSignal(); + m_values[i] = 0; + m_slopes[i] = 0; + m_nextvalues[i] = 0; + m_nextmidpts[i] = 0; + m_curves[i] = 0; + } + + FLEXT_ADDATTR_VAR("frequency", get_freq, set_freq); + FLEXT_ADDATTR_VAR("interpolation_method",get_imethod, set_imethod); + + if (argc > 0) + { + CHAOS_INIT(freq, GetAInt(argv[0])); + } + else + { + CHAOS_INIT(freq, 440); + } + + if (argc > 1) + { + CHAOS_INIT(imethod, GetAInt(argv[1])); + } + else + { + CHAOS_INIT(imethod, 0); + } + m_phase = 0; + } + + ~chaos_dsp() + { + delete[] m_values; + delete[] m_slopes; + delete[] m_nextvalues; + delete[] m_nextmidpts; + delete[] m_curves; + } + +public: + /* signal functions: */ + /* for frequency = sr */ + void m_signal_(int n, t_sample *const *insigs,t_sample *const *outsigs); + /* sample & hold */ + void m_signal_n(int n, t_sample *const *insigs,t_sample *const *outsigs); + /* sample & hold for high frequencies */ + void m_signal_n_hf(int n, t_sample *const *insigs,t_sample *const *outsigs); + /* linear interpolation */ + void m_signal_l(int n, t_sample *const *insigs,t_sample *const *outsigs); + /* linear interpolation for high frequencies */ + void m_signal_l_hf(int n, t_sample *const *insigs,t_sample *const *outsigs); + /* cubic interpolation */ + void m_signal_c(int n, t_sample *const *insigs,t_sample *const *outsigs); + /* cubic interpolation for high frequencies */ + void m_signal_c_hf(int n, t_sample *const *insigs,t_sample *const *outsigs); + + virtual void CbSignal() + { + (this->*m_routine)(Blocksize(),InSig(),OutSig()); + } + + virtual bool CbDsp() + { + m_sr = Samplerate(); + set_freq(m_freq); /* maybe we have to change the interpolation mode */ + return true; + } + + void (thisType::*m_routine)(int n, t_sample *const *insigs,t_sample *const *outsigs); + + /* local data for system, output and interpolation */ + system m_system; /* the system */ + + t_sample * m_values; /* actual value */ + t_sample * m_slopes; /* actual slope for cubic interpolation */ + + t_sample * m_nextvalues; + t_sample * m_nextmidpts; + t_sample * m_curves; + + /* local data for signal functions */ + float m_freq; /* frequency of oscillations */ + float m_invfreq; /* inverse frequency */ + float m_phase; /* phase */ + float m_sr; /* sample rate */ + + int m_imethod; /* interpolation method */ + + void get_imethod(int &i) + { + i = m_imethod; + } + + void set_imethod(int i) + { + int imethod = m_imethod; + if( (i >= 0) && (i <= 2) ) + { + m_imethod = i; + switch (i) + { + case 0: + m_routine = &thisType::m_signal_n; + break; + case 1: + m_routine = &thisType::m_signal_l; + break; + case 2: + m_routine = &thisType::m_signal_c; + break; + } + } + else + { + post("interpolation method out of range"); + return; + } + + if (imethod == 0) + for (int j = 0; j != m_system.get_num_eq(); ++j) + { + m_values[j] = m_system.get_data(j); + m_slopes[j] = 0; + } + + if(i == 2 && imethod != 2) + { + for (int j = 0; j != m_system.get_num_eq(); ++j) + { + m_phase = 0; /* reschedule to avoid click, find a better way later*/ + m_nextvalues[j] = m_values[j]; + m_nextmidpts[j] = m_values[j]; + } + } + set_freq(m_freq); + } + + void get_freq(float &f) + { + f = m_freq; + } + + void set_freq(float f) + { + if (f < 0) /* we can't go back in time :-) */ + f = -f; + + if( f <= m_sr * 0.01 ) + { + switch(m_imethod) + { + case 0: + m_routine = &thisType::m_signal_n; + break; + case 1: + m_routine = &thisType::m_signal_l; + break; + case 2: + m_routine = &thisType::m_signal_c; + break; + default: + assert(false); + } + } + else + { + switch(m_imethod) + { + case 0: + m_routine = &thisType::m_signal_n_hf; + break; + case 1: + m_routine = &thisType::m_signal_l_hf; + break; + case 2: + m_routine = &thisType::m_signal_c_hf; + break; + default: + assert(false); + } + } + + m_freq = f; + m_invfreq = 1.f / f; + } + + FLEXT_CALLVAR_F(get_freq, set_freq); + FLEXT_CALLVAR_I(get_imethod, set_imethod); +}; + + + +/* create constructor / destructor */ +#define CHAOS_DSP_INIT(SYSTEM, ATTRIBUTES) \ +FLEXT_HEADER(SYSTEM##_dsp, chaos_dsp<SYSTEM>) \ + \ +SYSTEM##_dsp(int argc, t_atom* argv): \ + chaos_dsp<SYSTEM>(argc, argv) \ +{ \ + ATTRIBUTES; \ +} \ + \ +FLEXT_ATTRVAR_F(m_freq); \ +FLEXT_ATTRVAR_I(m_imethod); + + + +template <class system> +void chaos_dsp<system>::m_signal_(int n, t_sample *const *insigs, + t_sample *const *outsigs) +{ + int outlets = m_system.get_num_eq(); + + for (int i = 0; i!=n; ++i) + { + m_system.m_step(); + m_system.m_bash_denormals(); + m_system.m_verify(); + + for (int j = 0; j != outlets; ++j) + { + outsigs[j][i] = m_system.get_data(j); + } + } +} + + +template <class system> +void chaos_dsp<system>::m_signal_n_hf(int n, t_sample *const *insigs, + t_sample *const *outsigs) +{ + int outlets = m_system.get_num_eq(); + + float phase = m_phase; + + int offset = 0; + while (n) + { + while (phase <= 0) + { + m_system.m_step(); + m_system.m_bash_denormals(); + m_system.m_verify(); + + phase += m_sr * m_invfreq; + } + int next = (phase < n) ? int(ceilf (phase)) : n; + n -= next; + phase -=next; + + for (int i = 0; i != outlets; ++i) + { + SetSamples(outsigs[i]+offset, next, m_system.get_data(i)); + } + offset += next; + } + m_phase = phase; +} + + +template <class system> +void chaos_dsp<system>::m_signal_n(int n, t_sample *const *insigs, + t_sample *const *outsigs) +{ + int outlets = m_system.get_num_eq(); + + int phase = int(m_phase); + + int offset = 0; + while (n) + { + if (phase == 0) + { + m_system.m_step(); + m_system.m_bash_denormals(); + m_system.m_verify(); + + phase = int (m_sr * m_invfreq); + } + + int next = (phase < n) ? phase : n; + n -= next; + phase -=next; + + for (int i = 0; i != outlets; ++i) + { + SetSamples(outsigs[i]+offset, next, m_system.get_data(i)); + } + offset += next; + } + m_phase = phase; +} + +/* linear and cubic interpolation adapted from supercollider by James McCartney */ +template <class system> +void chaos_dsp<system>::m_signal_l(int n, t_sample *const *insigs, + t_sample *const *outsigs) +{ + int outlets = m_system.get_num_eq(); + + int phase = int(m_phase); + + int i = 0; + + while (n) + { + if (phase == 0) + { + m_system.m_step(); + m_system.m_bash_denormals(); + m_system.m_verify(); + + phase = int (m_sr * m_invfreq); + + for (int j = 0; j != outlets; ++j) + m_slopes[j] = (m_system.get_data(j) - m_values[j]) / phase; + } + + int next = (phase < n) ? phase : n; + n -= next; + phase -=next; + + while (next--) + { + for (int j = 0; j != outlets; ++j) + { + outsigs[j][i] = m_values[j]; + m_values[j]+=m_slopes[j]; + } + ++i; + } + } + m_phase = phase; +} + + + +template <class system> +void chaos_dsp<system>::m_signal_l_hf(int n, t_sample *const *insigs, + t_sample *const *outsigs) +{ + int outlets = m_system.get_num_eq(); + + float phase = m_phase; + + int i = 0; + + while (n) + { + if (phase <= 0) + { + m_system.m_step(); + m_system.m_bash_denormals(); + m_system.m_verify(); + + phase = m_sr * m_invfreq; + + for (int j = 0; j != outlets; ++j) + m_slopes[j] = (m_system.get_data(j) - m_values[j]) / phase; + } + + int next = (phase < n) ? int(ceilf (phase)) : n; + n -= next; + phase -=next; + + while (next--) + { + for (int j = 0; j != outlets; ++j) + { + outsigs[j][i] = m_values[j]; + m_values[j]+=m_slopes[j]; + } + ++i; + } + } + m_phase = phase; +} + + +template <class system> +void chaos_dsp<system>::m_signal_c(int n, t_sample *const *insigs, + t_sample *const *outsigs) +{ + int outlets = m_system.get_num_eq(); + + int phase = int(m_phase); + + int i = 0; + + while (n) + { + if (phase == 0) + { + m_system.m_step(); + m_system.m_bash_denormals(); + m_system.m_verify(); + + phase = int (m_sr * m_invfreq); + phase = (phase > 2) ? phase : 2; + + for (int j = 0; j != outlets; ++j) + { + t_sample value = m_nextvalues[j]; + m_nextvalues[j]= m_system.get_data(j); + + m_values[j] = m_nextmidpts[j]; + m_nextmidpts[j] = (m_nextvalues[j] + value) * 0.5f; + + float fseglen = (float)phase; + m_curves[j] = 2.f * (m_nextmidpts[j] - m_values[j] - + fseglen * m_slopes[j]) + / (fseglen * fseglen + fseglen); + } + } + + int next = (phase < n) ? phase : n; + n -= next; + phase -=next; + + while (next--) + { + for (int j = 0; j != outlets; ++j) + { + outsigs[j][i] = m_values[j]; + m_slopes[j]+=m_curves[j]; + m_values[j]+=m_slopes[j]; + } + ++i; + } + } + m_phase = phase; +} + + +template <class system> +void chaos_dsp<system>::m_signal_c_hf(int n, t_sample *const *insigs, + t_sample *const *outsigs) +{ + int outlets = m_system.get_num_eq(); + + float phase = m_phase; + + int i = 0; + + while (n) + { + if (phase == 0) + { + m_system.m_step(); + m_system.m_bash_denormals(); + m_system.m_verify(); + + + phase = int (m_sr * m_invfreq); + phase = (phase > 2) ? phase : 2; + + for (int j = 0; j != outlets; ++j) + { + t_sample value = m_nextvalues[j]; + m_nextvalues[j]= m_system.get_data(j); + + m_values[j] = m_nextmidpts[j]; + m_nextmidpts[j] = (m_nextvalues[j] + value) * 0.5f; + + float fseglen = (float)phase; + m_curves[j] = 2.f * (m_nextmidpts[j] - m_values[j] - + fseglen * m_slopes[j]) + / (fseglen * fseglen + fseglen); + } + } + + int next = (phase < n) ? int(ceilf (phase)) : n; + n -= next; + phase -=next; + + while (next--) + { + for (int j = 0; j != outlets; ++j) + { + outsigs[j][i] = m_values[j]; + m_slopes[j]+=m_curves[j]; + m_values[j]+=m_slopes[j]; + } + ++i; + } + } + m_phase = phase; +} |