/* sc4pd Median, Median~ Copyright (c) 2004 Tim Blechmann. This code is derived from: SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com 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. Based on: PureData by Miller Puckette and others. http://www.crca.ucsd.edu/~msp/software.html FLEXT by Thomas Grill http://www.parasitaere-kapazitaeten.net/ext SuperCollider by James McCartney http://www.audiosynth.com Coded while listening to: Morton Feldman: For John Cage */ #include "sc4pd.hpp" /* ------------------------ Median(~) ---------------------------------*/ const int kMAXMEDIANSIZE = 32; class median_shared { public: inline void Init(long size, float value); inline float Insert(float value); private: float m_medianValue[kMAXMEDIANSIZE]; long m_medianAge[kMAXMEDIANSIZE]; long m_medianSize, m_medianIndex; }; void median_shared::Init(long size, float value) { // initialize the arrays with the first value m_medianSize = size; for (int i=0; i>1] last = m_medianSize - 1; // find oldest bin and age the other bins. for (i=0; i m_medianValue[pos+1]) { m_medianValue[pos] = m_medianValue[pos+1]; m_medianAge[pos] = m_medianAge[pos+1]; pos++; } m_medianValue[pos] = value; m_medianAge[pos] = 0; // this is the newest bin, age = 0 return m_medianValue[m_medianSize>>1]; } /* ------------------------ Median~ -----------------------------------*/ class Median_ar :public sc4pd_dsp { FLEXT_HEADER(Median_ar,sc4pd_dsp); public: Median_ar(int argc, t_atom * argv); protected: virtual void m_signal(int n, t_sample *const *in, t_sample *const *out); virtual void m_dsp (int n,t_signalvec const * insigs, t_signalvec const * outsigs); void m_set(float f) { m_size=(int)f; Median.Init(m_size,Median.Insert(0)); /* this is not beautiful, but i'm not aware of a nicer way */ } private: FLEXT_CALLBACK_F(m_set); median_shared Median; //median int m_size; //median size }; FLEXT_LIB_DSP_V("Median~",Median_ar); Median_ar::Median_ar(int argc,t_atom * argv) { FLEXT_ADDMETHOD_(0,"set",m_set); AtomList Args(argc,argv); m_size=sc_getfloatarg(Args,0); AddOutSignal(); } void Median_ar::m_dsp(int n,t_signalvec const * insigs, t_signalvec const * outsigs) { Median.Init(m_size,0); //how is this done in SuperCollider? } void Median_ar::m_signal(int n, t_sample *const *in, t_sample *const *out) { t_sample *nout = *out; t_sample *nin = *in; for (int i = 0; i!= n;++i) { (*(nout)++) = Median.Insert(*(nin)++); } } /* ------------------------ Median ------------------------------------*/ class Median_kr :public sc4pd_dsp { FLEXT_HEADER(Median_kr,sc4pd_dsp); public: Median_kr(int argc, t_atom * argv); protected: void m_set(float f) { m_size=(int)f; Median.Init(m_size,Median.Insert(0)); /* this is not beautiful, but i'm not aware of a nicer way */ } void m_perform(float f); private: FLEXT_CALLBACK_F(m_set); FLEXT_CALLBACK_F(m_perform); median_shared Median; //median int m_size; //median size }; FLEXT_LIB_V("Median",Median_kr); Median_kr::Median_kr(int argc,t_atom * argv) { FLEXT_ADDMETHOD_(0,"set",m_set); FLEXT_ADDMETHOD(0,m_perform); AtomList Args(argc,argv); m_size=(int)sc_getfloatarg(Args,0); float m_set=sc_getfloatarg(Args,1); Median.Init(m_size,m_set); AddOutFloat(); } void Median_kr::m_perform(float f) { ToOutFloat(0,Median.Insert(f)); }