Mozzi  alpha 0.01.1t
sound synthesis library for Arduino
 All Classes Functions Typedefs
Sample.h
00001 /*
00002  * Sample.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 SAMPLE_H_
00026 #define SAMPLE_H_
00027 
00028 #include "Arduino.h"
00029 #include "MozziGuts.h"
00030 #include "fixedMath.h"
00031 #include <util/atomic.h>
00032 
00033 
00034 // fractional bits for sample index precision
00035 #define SAMPLE_F_BITS 16
00036 #define SAMPLE_F_BITS_AS_MULTIPLIER 65536
00037 
00038 // phmod_proportion is an 1n15 fixed-point number only using
00039 // the fractional part and the sign bit
00040 #define SAMPLE_PHMOD_BITS 16
00041 
00042 
00061 template <unsigned int NUM_TABLE_CELLS, unsigned int UPDATE_RATE>
00062 class Sample
00063 {
00064 
00065 public:
00066 
00073                 Sample(const char * TABLE_NAME):table(TABLE_NAME)
00074                 {
00075                                 setLoopingOff();
00076                                 rangeWholeSample();
00077                 }
00078 
00079 
00080 
00085                 Sample()
00086                 {
00087                                 setLoopingOff();
00088                                 rangeWholeSample();
00089                 }
00090 
00091 
00095                 inline
00096                 void setTable(const char * TABLE_NAME)
00097                 {
00098                                 table = TABLE_NAME;
00099                 }
00100 
00101 
00105                 inline
00106                 void setStart(unsigned int start)
00107                 {
00108                                 startpos_fractional = (unsigned long) start << SAMPLE_F_BITS;
00109                 }
00110 
00111 
00114                 inline
00115                 void start()
00116                 {
00117                                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
00118                                 {
00119                                                 phase_fractional = startpos_fractional;
00120                                 }
00121                 }
00122 
00123 
00127                 inline
00128                 void start(unsigned int startpos)
00129                 {
00130                                 setStart(startpos);
00131                                 start();
00132                 }
00133 
00134 
00138                 inline
00139                 void setEnd(unsigned int end)
00140                 {
00141                                 endpos_fractional = (unsigned long) end << SAMPLE_F_BITS;
00142                 }
00143 
00144 
00147                 inline
00148                 void rangeWholeSample()
00149                 {
00150                                 endpos_fractional = 0;
00151                                 endpos_fractional = (unsigned long) NUM_TABLE_CELLS << SAMPLE_F_BITS;
00152                 }
00153 
00154 
00157                 inline
00158                 void setLoopingOn()
00159                 {
00160                                 looping=true;
00161                 }
00162 
00163 
00166                 inline
00167                 void setLoopingOff()
00168                 {
00169                                 looping=false;
00170                 }
00171 
00172 
00180                 inline
00181                 char next() // 4us
00182                 {
00183                                 char out = 0;
00184                                 if (!looping)
00185                                 {
00186                                                 if (phase_fractional<endpos_fractional){
00187                                                                 out = (char)pgm_read_byte_near(table + (phase_fractional >> SAMPLE_F_BITS)); 
00188                                                                 incrementPhase();
00189                                                 }
00190                                 }
00191                                 else
00192                                 {
00193                                                 if (phase_fractional>endpos_fractional)
00194                                                                 phase_fractional = startpos_fractional + (phase_fractional - endpos_fractional);
00195                                                 
00196                                                 out = (char)pgm_read_byte_near(table + (phase_fractional >> SAMPLE_F_BITS));
00197                                                 incrementPhase();
00198                                 }
00199                                 return out;
00200                 }
00201 
00202 
00203                 // Not readjusted for arbitrary table length yet
00204                 //
00205                 // /** Returns the next sample given a phase modulation value.
00206                 // @param a phase modulation value given as a proportion of the wave. The
00207                 // phmod_proportion parameter is a Q15n16 fixed-point number where to fractional
00208                 // n16 part represents -1 to 1, modulating the phase by one whole table length in
00209                 // each direction.
00210                 // @return a sample from the table.
00211                 // */
00212                 // inline
00213                 // char phMod(long phmod_proportion)
00214                 // {
00215                 //              incrementPhase();
00216                 //              return (char)pgm_read_byte_near(table + (((phase_fractional+(phmod_proportion * NUM_TABLE_CELLS))>>SAMPLE_SAMPLE_F_BITS) & (NUM_TABLE_CELLS - 1)));
00217                 // }
00218 
00219 
00220 
00228                 inline
00229                 void setFreq (unsigned int frequency) {
00230                                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
00231                                 {
00232                                                 phase_increment_fractional = ((((unsigned long)NUM_TABLE_CELLS<<ADJUST_FOR_NUM_TABLE_CELLS)*frequency)/UPDATE_RATE) << (SAMPLE_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS);
00233                                 }
00234                 }
00235 
00236 
00242                 inline
00243                 void setFreq(float frequency)
00244                 { // 1 us - using float doesn't seem to incur measurable overhead with the oscilloscope
00245                                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
00246                                 {
00247                                                 phase_increment_fractional = (unsigned long)((((float)NUM_TABLE_CELLS * frequency)/UPDATE_RATE) * SAMPLE_F_BITS_AS_MULTIPLIER);
00248                                 }
00249                 }
00250 
00251                 
00260                 inline
00261                 void setFreq_Q24n8(Q24n8 frequency)
00262                 {
00263                                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
00264                                 {
00265                                                 //phase_increment_fractional = (frequency* (NUM_TABLE_CELLS>>3)/(UPDATE_RATE>>6)) << (F_BITS-(8-3+6));
00266                                                 phase_increment_fractional = (((((unsigned long)NUM_TABLE_CELLS<<ADJUST_FOR_NUM_TABLE_CELLS)>>3)*frequency)/(UPDATE_RATE>>6)) 
00267                                                                 << (SAMPLE_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS - (8-3+6));
00268                                 }
00269                 }
00270                 
00271                 
00277                 inline
00278                 char atIndex(unsigned int index)
00279                 {
00280                                 return (char)pgm_read_byte_near(table + (index & (NUM_TABLE_CELLS - 1)));
00281                 }
00282 
00283 
00294                 inline
00295                 unsigned long phaseIncFromFreq(unsigned int frequency)
00296                 {
00297                                 return (((unsigned long)frequency * NUM_TABLE_CELLS)/UPDATE_RATE) << SAMPLE_F_BITS;
00298                 }
00299 
00300 
00304                 inline
00305                 void setPhaseInc(unsigned long phaseinc_fractional)
00306                 {
00307                                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
00308                                 {
00309                                                 phase_increment_fractional = phaseinc_fractional;
00310                                 }
00311                 }
00312 
00313 
00314 private:
00315 
00316                 
00319                 static const unsigned char ADJUST_FOR_NUM_TABLE_CELLS = (NUM_TABLE_CELLS<2048) ? 8 : 0;
00320 
00321                 
00324                 inline
00325                 void incrementPhase()
00326                 {
00327                                 phase_fractional += phase_increment_fractional;
00328                 }
00329 
00330 
00331                 volatile unsigned long phase_fractional;
00332                 volatile unsigned long phase_increment_fractional;
00333                 const char * table;
00334                 bool looping;
00335                 unsigned long startpos_fractional, endpos_fractional;
00336 };
00337 
00338 #endif /* SAMPLE_H_ */