Browse Source

Basic oscillators done. Implemented gamma-style ()-operator overloading for next sample request. Moved ugens to new namespace 'ugen'.

akshaycadambi 5 years ago
parent
commit
6665cd3757
6 changed files with 247 additions and 41 deletions
  1. 37 0
      synth.cpp
  2. 30 0
      synth.h
  3. 41 30
      table.cpp
  4. 13 11
      table.h
  5. 81 0
      ugens.cpp
  6. 45 0
      ugens.h

+ 37 - 0
synth.cpp

@@ -0,0 +1,37 @@
+#include "synth.h"
+#include "math.h"
+
+synth::WavetableSynth::WavetableSynth()
+{
+    current_phase = 0;
+    tbl = NULL;
+}
+
+sample synth::WavetableSynth::freqMod(float freq)
+{
+    phase_inc = floor( frequency * (double) Tables::length() / SystemSR );
+    return this->tick();
+}
+
+
+inline sample synth::WavetableSynth::tick()
+{
+    /*
+     * Basic tick function template. Use this for simple traversal within the wavetable.
+     * It is a virtual function and can be overridden based on specific requirements of
+     * the derived class.
+     */
+
+    sample outValue = *(tbl + current_phase);
+    current_phase += phase_inc;
+    current_phase = current_phase & Tables::phase_mask();
+    return outValue;
+}
+
+void synth::WavetableSynth::setFreq(float freq)
+{
+    frequency = freq;
+    phase_inc = lrint( frequency * (double) Tables::length() / SystemSR );
+}
+
+

+ 30 - 0
synth.h

@@ -0,0 +1,30 @@
+#ifndef SYNTH
+#define SYNTH
+
+#include <inttypes.h>
+#include <cstdlib>
+#include "table.h"
+#include "math.h"
+
+namespace synth{
+
+class WavetableSynth
+    {
+    public:
+        float frequency;
+        float phase;
+        int current_phase;
+        int phase_inc;
+        sample *tbl;
+
+        WavetableSynth();
+        void setFreq(float freq);
+        sample freqMod(float freq);
+        virtual inline sample tick();
+
+protected:
+    };
+
+}   // End of synth namespace
+
+#endif // SYNTH

+ 41 - 30
table.cpp

@@ -1,42 +1,53 @@
 #include "table.h"
-#include "inttypes.h"
 #include <math.h>
 #include <stdlib.h>
 
-double * gen::sine(int len)
+sample * gen::sine(int len)
 {
-    double *SineTable = (double* ) malloc(sizeof(double) * len);
+    sample *SineTable = (sample* ) malloc(sizeof(sample) * len);
     for (int i=0; i<len; i++)
     {
-        *(SineTable+i) = sin(2*M_PI*i/len);
+        *(SineTable+i) = 128 + 127 * sin(2*M_PI*i/len);
     }
     return SineTable;
 }
 
-double * gen::tri(int len)
+sample * gen::tri(int len)
 {
-    double *TriTable = (double* ) malloc(sizeof(double) * len);
-    for (int i=0; i<len; i++)
+    sample *TriTable = (sample* ) malloc(sizeof(sample) * len);
+    for (int i=0 ; i<=len/4; i++)
+    {
+        TriTable[i] = 128 + 127*4.0/len * i;
+    }
+    for (int i=1; i<=len/2; i++)
+    {
+        TriTable[i + len/4] = 255 - 255*2.0/len * i;
+    }
+    for (int i=1; i<=len/4; i++)
     {
-        *TriTable = sin(2*M_PI*i/len);
+        TriTable[i + 3*len/4] = 127*4.0/len * i;
     }
+
     return TriTable;
 }
 
-double * gen::saw(int len)
+sample * gen::saw(int len)
 {
-    double *SawTable = (double* ) malloc(sizeof(double) * len);
-    for (int i=0; i<len; i++)
-    {
-            *(SawTable+i) += sin(2*M_PI * i / len);
-    }
+    /* Square doesn't *really* have a wavetable. It simple does a comparison between
+     * the current phase and 0.5*table_length and returns either a 1 or 0.
+     *
+     * To avoid an extra division step, 0.5*table_length is stored in the table.
+     */
+    sample *SawTable = (sample* ) malloc(sizeof(sample));
+    *SawTable = len/2.0;
     return SawTable;
 }
 
-double * gen::square(int len)
+sample * gen::square(int len)
 {
-    double *SquareTable = (double* ) malloc(sizeof(double) * len);
-    for (int i=0; i<len; i++)
+    // NOT USED
+    sample *SquareTable = (sample* ) malloc(sizeof(sample) * len);
+    for (int i=0; i<len/2.0; i++)
     {
         *SquareTable = sin(2*M_PI*i/len);
     }
@@ -45,7 +56,7 @@ double * gen::square(int len)
 
 //*****************************************************
 
-int Tables::table_length(void)
+int Tables::length(void)
 {
     static int table_length = DEFAULT_TABLE_LENGTH;
     return table_length;
@@ -57,46 +68,46 @@ int Tables::phase_mask(void)
     return table_length;
 }
 
-double * Tables::sine()
+sample * Tables::sine()
 {
-    static double* tbl_sine;
+    static sample* tbl_sine;
 
     if (tbl_sine == NULL)
        {
-           tbl_sine = gen::sine( Tables::table_length() );
+           tbl_sine = gen::sine( Tables::length() );
        }
        return tbl_sine;
 }
 
-double * Tables::tri()
+sample * Tables::tri()
 {
-    static double* tbl_tri;
+    static sample* tbl_tri;
 
     if (tbl_tri == NULL)
        {
-           tbl_tri = gen::tri(Tables::table_length());
+           tbl_tri = gen::tri(Tables::length());
        }
        return tbl_tri;
 }
 
-double * Tables::saw()
+sample * Tables::saw()
 {
-    static double* tbl_saw;
+    static sample* tbl_saw;
 
     if (tbl_saw == NULL)
        {
-           tbl_saw = gen::saw(Tables::table_length());
+           tbl_saw = gen::saw(Tables::length());
        }
        return tbl_saw;
 }
 
-double * Tables::square()
+sample * Tables::square()
 {
-    static double* tbl_square;
+    static sample* tbl_square;
 
     if (tbl_square == NULL)
        {
-           tbl_square = gen::square(Tables::table_length());
+           tbl_square = gen::square(Tables::length());
        }
        return tbl_square;
 }

+ 13 - 11
table.h

@@ -4,30 +4,32 @@
 #include "inttypes.h"
 #include <cstdlib>
 
-#define DEFAULT_TABLE_LENGTH 1023
-#define DEFAULT_PHASE_MASK DEFAULT_TABLE_LENGTH
+#define DEFAULT_TABLE_LENGTH 1024
+#define DEFAULT_PHASE_MASK DEFAULT_TABLE_LENGTH-1
+
+typedef unsigned int sample;
 
 // Global Sample Rate
 #define SystemSR 44100
 
 namespace gen {
     // Table filling functions
-    double *sine(int len);
-    double *tri(int len);
-    double *saw(int len);
-    double *square(int len);
+    sample *sine(int len);
+    sample *tri(int len);
+    sample *saw(int len);
+    sample *square(int len);
 }
 
 namespace Tables{
 
     // Table containers
     //  These funcitons return singletons of a table
-    int table_length(void);
+    int length(void);
     int phase_mask(void);
-    double * sine();
-    double * tri();
-    double * saw();
-    double * square();
+    sample * sine();
+    sample * tri();
+    sample * saw();
+    sample * square();
 
 }
 

+ 81 - 0
ugens.cpp

@@ -0,0 +1,81 @@
+#include <iostream>
+#include "ugens.h"
+#include "math.h"
+
+//--------------------------------------------
+
+ugen::Sine::Sine(float freq)
+{
+    setFreq(freq);
+    tbl = Tables::sine();
+}
+
+sample ugen::Sine::operator()(void)
+{
+    return tick();
+}
+
+
+//--------------------------------------------
+
+ugen::Tri::Tri(float freq)
+{
+    setFreq(freq);
+    tbl = Tables::tri();
+}
+
+sample ugen::Tri::operator()(void)
+{
+    return tick();
+}
+
+
+//--------------------------------------------
+
+ugen::Saw::Saw(float freq)
+{
+    setFreq(freq);
+    tbl = Tables::saw();
+}
+
+sample ugen::Saw::operator()(void)
+{
+    return tick();
+}
+
+//--------------------------------------------
+
+ugen::ReverseSaw::ReverseSaw(float freq)
+{
+    setFreq(freq);
+    tbl = Tables::saw();
+}
+
+sample ugen::ReverseSaw::operator()(void)
+{
+    /* This is a neat little trick. It simply reverses the indexing of the saw
+     * table to give the reverse saw.
+     * The change in indexing uses bitwise operations so it is very fast!
+     */
+    sample outValue = *(tbl + (~current_phase & Tables::phase_mask()) );
+    current_phase += phase_inc;
+    current_phase = current_phase & Tables::phase_mask();
+    return outValue;
+}
+
+//--------------------------------------------
+
+ugen::Square::Square(float freq)
+{
+    setFreq(freq);
+    // Note. This is optimized. See tables.cpp for details on saw table.
+    tbl = Tables::saw();
+}
+
+sample ugen::Square::operator()(void)
+{
+    sample outValue = ( current_phase <= *tbl );
+    current_phase += phase_inc;
+    current_phase = current_phase & Tables::phase_mask();
+    return outValue;
+}

+ 45 - 0
ugens.h

@@ -0,0 +1,45 @@
+#ifndef UGENS
+#define UGENS
+
+#include "synth.h"
+
+namespace ugen{
+
+class Sine : public synth::WavetableSynth
+    {
+    public:
+        Sine(float freq);
+        sample operator()(void);
+    };
+
+class Tri : public synth::WavetableSynth
+    {
+    public:
+        Tri(float freq);
+        sample operator()(void);
+    };
+
+class Saw: public synth::WavetableSynth
+    {
+    public:
+        Saw(float freq);
+        sample operator()(void);
+    };
+
+class ReverseSaw: public synth::WavetableSynth
+    {
+    public:
+        ReverseSaw(float freq);
+        sample operator()(void);
+    };
+
+class Square: public synth::WavetableSynth
+    {
+    public:
+        Square(float freq);
+        sample operator()(void);
+    };
+
+} // End of ugen namespace
+
+#endif