Mozzi  alpha 0.01.1t
sound synthesis library for Arduino
 All Classes Functions Typedefs
Oscil.h
00001 /*
00002  * Oscil.h
00003  *
00004  * Oscil.h owes much to AF_precision_synthesis.pde, 2009, Adrian Freed.
00005  *
00006  * Copyright 2012 Tim Barrass, 2009 Adrian Freed.
00007  *
00008  * This file is part of Mozzi.
00009  *
00010  * Mozzi is free software: you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation, either version 3 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * Mozzi is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with Mozzi.  If not, see <http://www.gnu.org/licenses/>.
00022  *
00023  */
00024 
00025 #ifndef OSCIL_H_
00026 #define OSCIL_H_
00027 
00028 #include "Arduino.h"
00029 #include "MozziGuts.h"
00030 #include "fixedMath.h"
00031 #include <util/atomic.h>
00032 
00033 #ifdef OSCIL_DITHER_PHASE
00034 #include "utils.h"
00035 #endif
00036 
00037 // fractional bits for oscillator index precision
00038 #define OSCIL_F_BITS 16
00039 #define OSCIL_F_BITS_AS_MULTIPLIER 65536
00040 
00041 // phmod_proportion is an 1n15 fixed-point number only using
00042 // the fractional part and the sign bit
00043 #define OSCIL_PHMOD_BITS 16
00044 
00045 
00046                 
00069 //template <unsigned int NUM_TABLE_CELLS, unsigned int UPDATE_RATE, bool DITHER_PHASE=false>
00070 template <unsigned int NUM_TABLE_CELLS, unsigned int UPDATE_RATE>
00071 class Oscil
00072 {
00073                 
00074                 
00075 public:
00081                 Oscil(const char * TABLE_NAME):table(TABLE_NAME)
00082                 {}
00083                 
00084                 
00091                 Oscil()
00092                 {}
00093 
00094 
00099                 inline
00100                 char next()
00101                 {
00102                                 incrementPhase();
00103                                 return readTable();
00104                 }
00105 
00106 
00110                 void setTable(const char * TABLE_NAME)
00111                 {
00112                                 table = TABLE_NAME;
00113                 }
00114 
00115 
00120                 // This could be called in the control interrupt, so phase_fractional should really be volatile,
00121                 // but that could limit optimisation.  Since phase_fractional gets changed often in updateAudio()
00122                 // (in loop()), it's probably worth keeping it nonvolatile until it causes problems
00123                 void setPhase(unsigned int phase)
00124                 {
00125                                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
00126                                 {
00127                                                 phase_fractional = (unsigned long)phase << OSCIL_F_BITS;
00128                                 }
00129                 }
00130                 
00135                 // This could be called in the control interrupt, so phase_fractional should really be volatile,
00136                 // but that could limit optimisation.  Since phase_fractional gets changed often in updateAudio()
00137                 // (in loop()), it's probably worth keeping it nonvolatile until it causes problems
00138                 void setPhaseFractional(unsigned long phase)
00139                 {
00140                                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
00141                                 {
00142                                                 phase_fractional = phase;
00143                                 }
00144                 }
00145                 
00146                 
00150                 unsigned long getPhaseFractional()
00151                 {
00152                                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
00153                                 {
00154                                                 return phase_fractional;;
00155                                 }
00156                 }
00157                 
00158 
00159 
00167                 // PM: cos((angle += incr) + change)
00168                 // FM: cos(angle += (incr + change))
00169                 // The ratio of deviation to modulation frequency is called the "index of modulation". ( I = d / Fm )
00170                 inline
00171                 char phMod(Q15n16 phmod_proportion)
00172                 {
00173                                 incrementPhase();
00174                                 return (char)pgm_read_byte_near(table + (((phase_fractional+(phmod_proportion * NUM_TABLE_CELLS))>>OSCIL_F_BITS) & (NUM_TABLE_CELLS - 1)));
00175                 }
00176 
00177                 
00185                 inline
00186                 void setFreq (unsigned int frequency) {
00187                                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
00188                                 {
00189                                                 phase_increment_fractional = ((((unsigned long)NUM_TABLE_CELLS<<ADJUST_FOR_NUM_TABLE_CELLS)*frequency)/UPDATE_RATE) << (OSCIL_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS);
00190                                 }
00191                 }
00192                 
00193                 
00199                 inline
00200                 void setFreq(float frequency)
00201                 { // 1 us - using float doesn't seem to incur measurable overhead with the oscilloscope
00202                                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
00203                                 {
00204                                                 phase_increment_fractional = (unsigned long)((((float)NUM_TABLE_CELLS * frequency)/UPDATE_RATE) * OSCIL_F_BITS_AS_MULTIPLIER);
00205                                 }
00206                 }
00207                 
00208                 
00216                 inline
00217                 void setFreq_Q24n8(Q24n8 frequency)
00218                 {
00219                                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
00220                                 {
00221                                                 //phase_increment_fractional = (frequency* (NUM_TABLE_CELLS>>3)/(UPDATE_RATE>>6)) << (F_BITS-(8-3+6));
00222                                                 phase_increment_fractional = (((((unsigned long)NUM_TABLE_CELLS<<ADJUST_FOR_NUM_TABLE_CELLS)>>3)*frequency)/(UPDATE_RATE>>6)) 
00223                                                                 << (OSCIL_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS - (8-3+6));
00224                                 }
00225                 }
00226 
00227 
00234                 inline
00235                 void setFreq_Q16n16(Q16n16 frequency)
00236                 {
00237                                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
00238                                 {
00239                                                 //phase_increment_fractional = ((frequency * (NUM_TABLE_CELLS>>7))/(UPDATE_RATE>>6)) << (F_BITS-16+1);
00240                                                 phase_increment_fractional = (((((unsigned long)NUM_TABLE_CELLS<<ADJUST_FOR_NUM_TABLE_CELLS)>>7)*frequency)/(UPDATE_RATE>>6)) 
00241                                                                 << (OSCIL_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS - 16 + 1);
00242 
00243                                 }
00244                 }
00245 
00246 
00252                 inline
00253                 char atIndex(unsigned int index)
00254                 {
00255                                 return (char)pgm_read_byte_near(table + (index & (NUM_TABLE_CELLS - 1)));
00256                 }
00257 
00258 
00269                 inline
00270                 //const 
00271                 unsigned long phaseIncFromFreq(unsigned int frequency)
00272                 {
00273                                 return (((unsigned long)frequency * NUM_TABLE_CELLS)/UPDATE_RATE) << OSCIL_F_BITS;
00274                 }
00275 
00276 
00280                 inline
00281                 void setPhaseInc(unsigned long phaseinc_fractional)
00282                 {
00283                                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
00284                                 {
00285                                                 phase_increment_fractional = phaseinc_fractional;
00286                                 }
00287                 }
00288 
00289                 
00290                 
00291 private:
00292 
00293 
00296                 static const unsigned char ADJUST_FOR_NUM_TABLE_CELLS = (NUM_TABLE_CELLS<2048) ? 8 : 0;
00297                 
00298                 
00301                 inline
00302                 void incrementPhase()
00303                 {
00304                                 //phase_fractional += (phase_increment_fractional | 1); // odd phase incr, attempt to reduce frequency spurs in output
00305                                 phase_fractional += phase_increment_fractional;
00306                 }
00307 
00308 
00311                 inline
00312                 char readTable()
00313                 {
00314 #ifdef OSCIL_DITHER_PHASE
00315                                 return (char)pgm_read_byte_near(table + (((phase_fractional + ((int)(xorshift96()>>16))) >> OSCIL_F_BITS) & (NUM_TABLE_CELLS - 1)));
00316 #else
00317                                 return (char)pgm_read_byte_near(table + ((phase_fractional >> OSCIL_F_BITS) & (NUM_TABLE_CELLS - 1)));
00318                                 //return (char)pgm_read_byte_near(table + (((phase_fractional >> OSCIL_F_BITS) | 1 ) & (NUM_TABLE_CELLS - 1))); odd phase, attempt to reduce frequency spurs in output
00319 #endif
00320                 }
00321 
00322 
00323                 unsigned long phase_fractional;
00324                 volatile unsigned long phase_increment_fractional; // volatile with atomic access because it can 
00325                                                                                                                                                                                                                                                                                                                                                                                                                                                 // be set in the updateControl() interrupt and 
00326                                                                                                                                                                                                                                                                                                                                                                                                                                                 // used in updateAudio(), which is outside the 
00327                                                                                                                                                                                                                                                                                                                                                                                                                                                 // interrupt.
00328                 const char * table;
00329 
00330 };
00331 
00332 
00333 #endif /* OSCIL_H_ */