![]() |
Mozzi
alpha 0.01.1t
sound synthesis library for Arduino
|
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_ */