aboutsummaryrefslogtreecommitdiff
path: root/sc4pd/source/Median.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sc4pd/source/Median.cpp')
-rw-r--r--sc4pd/source/Median.cpp213
1 files changed, 213 insertions, 0 deletions
diff --git a/sc4pd/source/Median.cpp b/sc4pd/source/Median.cpp
new file mode 100644
index 0000000..4383a1b
--- /dev/null
+++ b/sc4pd/source/Median.cpp
@@ -0,0 +1,213 @@
+/* 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<size; ++i) {
+ m_medianValue[i] = value;
+ m_medianAge[i] = i;
+ }
+}
+
+inline float median_shared::Insert(float value)
+{
+ long i, last, pos=-1;
+
+ // keeps a sorted list of the previous n=size values
+ // the oldest is removed and the newest is inserted.
+ // values between the oldest and the newest are shifted over by one.
+
+ // values and ages are both arrays that are 'size' long.
+ // the median value is always values[size>>1]
+
+ last = m_medianSize - 1;
+ // find oldest bin and age the other bins.
+ for (i=0; i<m_medianSize; ++i) {
+ if (m_medianAge[i] == last) { // is it the oldest bin ?
+ pos = i;
+ } else {
+ m_medianAge[i]++; // age the bin
+ }
+ }
+ // move values to fill in place of the oldest and make a space for the newest
+ // search lower if value is too small for the open space
+ while (pos != 0 && value < m_medianValue[pos-1]) {
+ m_medianValue[pos] = m_medianValue[pos-1];
+ m_medianAge[pos] = m_medianAge[pos-1];
+ pos--;
+ }
+ // search higher if value is too big for the open space
+ while (pos != last && value > 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));
+}