Mozzi  version 2015-05-11-20:23
sound synthesis library for Arduino
 All Classes Functions Typedefs Groups
Oscil.h
1 /*
2  * Oscil.h
3  *
4  * Oscil.h owes much to AF_precision_synthesis.pde, 2009, Adrian Freed.
5  *
6  * Copyright 2012 Tim Barrass, 2009 Adrian Freed.
7  *
8  * This file is part of Mozzi.
9  *
10  * Mozzi is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
11  *
12  */
13 
14 #ifndef OSCIL_H_
15 #define OSCIL_H_
16 
17 #if ARDUINO >= 100
18  #include "Arduino.h"
19 #else
20  #include "WProgram.h"
21 #endif
22 #include "MozziGuts.h"
23 #include "mozzi_fixmath.h"
24 #include <util/atomic.h>
25 
26 
27 #ifdef OSCIL_DITHER_PHASE
28 #include "mozzi_rand.h"
29 #endif
30 
31 // fractional bits for oscillator index precision
32 #define OSCIL_F_BITS 16
33 #define OSCIL_F_BITS_AS_MULTIPLIER 65536
34 
35 // phmod_proportion is an 15n16 fixed-point number
36 #define OSCIL_PHMOD_BITS 16
37 
38 
39 
63 //template <unsigned int NUM_TABLE_CELLS, unsigned int UPDATE_RATE, bool DITHER_PHASE=false>
64 template <uint16_t NUM_TABLE_CELLS, uint16_t UPDATE_RATE>
65 class Oscil
66 {
67 
68 
69 public:
75  Oscil(const int8_t * TABLE_NAME):table(TABLE_NAME)
76  {}
77 
78 
86  {}
87 
88 
92  inline
93  int8_t next()
94  {
95  incrementPhase();
96  return readTable();
97  }
98 
99 
103  void setTable(const int8_t * TABLE_NAME)
104  {
105  table = TABLE_NAME;
106  }
107 
108 
113  // This could be called in the control interrupt, so phase_fractional should really be volatile,
114  // but that could limit optimisation. Since phase_fractional gets changed often in updateAudio()
115  // (in loop()), it's probably worth keeping it nonvolatile until it causes problems
116  void setPhase(unsigned int phase)
117  {
118  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
119  {
120  phase_fractional = (unsigned long)phase << OSCIL_F_BITS;
121  }
122  }
123 
128  // This could be called in the control interrupt, so phase_fractional should really be volatile,
129  // but that could limit optimisation. Since phase_fractional gets changed often in updateAudio()
130  // (in loop()), it's probably worth keeping it nonvolatile until it causes problems
131  void setPhaseFractional(unsigned long phase)
132  {
133  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
134  {
135  phase_fractional = phase;
136  }
137  }
138 
139 
143  unsigned long getPhaseFractional()
144  {
145  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
146  {
147  return phase_fractional;
148  }
149  }
150 
151 
152 
160  // PM: cos((angle += incr) + change)
161  // FM: cos(angle += (incr + change))
162  // The ratio of deviation to modulation frequency is called the "index of modulation". ( I = d / Fm )
163  inline
164  int8_t phMod(Q15n16 phmod_proportion)
165  {
166  incrementPhase();
167  return (int8_t)pgm_read_byte_near(table + (((phase_fractional+(phmod_proportion * NUM_TABLE_CELLS))>>OSCIL_F_BITS) & (NUM_TABLE_CELLS - 1)));
168  }
169 
170 
178  inline
179  void setFreq (int frequency) {
180  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
181  {
182  // TB2014-8-20 change this following Austin Grossman's suggestion on user list
183  // https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/mozzi-users/u4D5NMzVnQs/pCmiWInFvrkJ
184  //phase_increment_fractional = ((((unsigned long)NUM_TABLE_CELLS<<ADJUST_FOR_NUM_TABLE_CELLS)*frequency)/UPDATE_RATE) << (OSCIL_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS);
185  // to this:
186  phase_increment_fractional = ((unsigned long)frequency) * ((OSCIL_F_BITS_AS_MULTIPLIER*NUM_TABLE_CELLS)/UPDATE_RATE);
187  }
188  }
189 
190 
196  inline
197  void setFreq(float frequency)
198  { // 1 us - using float doesn't seem to incur measurable overhead with the oscilloscope
199  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
200  {
201  phase_increment_fractional = (unsigned long)((((float)NUM_TABLE_CELLS * frequency)/UPDATE_RATE) * OSCIL_F_BITS_AS_MULTIPLIER);
202  }
203  }
204 
205 
213  inline
214  void setFreq_Q24n8(Q24n8 frequency)
215  {
216 
217  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
218  {
219  //phase_increment_fractional = (frequency* (NUM_TABLE_CELLS>>3)/(UPDATE_RATE>>6)) << (F_BITS-(8-3+6));
220  phase_increment_fractional = (((((unsigned long)NUM_TABLE_CELLS<<ADJUST_FOR_NUM_TABLE_CELLS)>>3)*frequency)/(UPDATE_RATE>>6))
221  << (OSCIL_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS - (8-3+6));
222 
223  // TB2014-8-20 change this following Austin Grossman's suggestion on user list
224  // https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/mozzi-users/u4D5NMzVnQs/pCmiWInFvrkJ
225  if ((256UL*NUM_TABLE_CELLS) >= UPDATE_RATE) {
226  phase_increment_fractional = ((unsigned long)frequency) * ((256UL*NUM_TABLE_CELLS)/UPDATE_RATE);
227  } else {
228  phase_increment_fractional = ((unsigned long)frequency) / (UPDATE_RATE/(256UL*NUM_TABLE_CELLS));
229  }
230  }
231 
232 
233  }
234 
235 
243  inline
244  void setFreq_Q16n16(Q16n16 frequency)
245  {
246  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
247  {
248  //phase_increment_fractional = ((frequency * (NUM_TABLE_CELLS>>7))/(UPDATE_RATE>>6)) << (F_BITS-16+1);
249  // TB2014-8-20 change this following Austin Grossman's suggestion on user list
250  // https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/mozzi-users/u4D5NMzVnQs/pCmiWInFvrkJ
251  //phase_increment_fractional = (((((uint32_t)NUM_TABLE_CELLS<<ADJUST_FOR_NUM_TABLE_CELLS)>>7)*frequency)/(UPDATE_RATE>>6))
252  // << (OSCIL_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS - 16 + 1);
253  if (NUM_TABLE_CELLS >= UPDATE_RATE) {
254  phase_increment_fractional = ((unsigned long)frequency) * (NUM_TABLE_CELLS/UPDATE_RATE);
255  } else {
256  phase_increment_fractional = ((unsigned long)frequency) / (UPDATE_RATE/NUM_TABLE_CELLS);
257  }
258 
259  }
260  }
261 /*
262  inline
263  void setFreqMidi(int8_t note_num) {
264  setFreq_Q16n16(mtof(note_num));
265  }
266 */
272  inline
273  int8_t atIndex(unsigned int index)
274  {
275  return (int8_t)pgm_read_byte_near(table + (index & (NUM_TABLE_CELLS - 1)));
276  }
277 
278 
289  inline
290  const
291  unsigned long phaseIncFromFreq(int frequency)
292  {
293  // TB2014-8-20 change this following Austin Grossman's suggestion on user list
294  // https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/mozzi-users/u4D5NMzVnQs/pCmiWInFvrkJ
295  //return (((unsigned long)frequency * NUM_TABLE_CELLS)/UPDATE_RATE) << OSCIL_F_BITS;
296  return ((unsigned long)frequency) * ((OSCIL_F_BITS_AS_MULTIPLIER*NUM_TABLE_CELLS)/UPDATE_RATE);
297  }
298 
299 
303  inline
304  void setPhaseInc(unsigned long phaseinc_fractional)
305  {
306  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
307  {
308  phase_increment_fractional = phaseinc_fractional;
309  }
310  }
311 
312 
313 
314 private:
315 
316 
319 static const uint8_t ADJUST_FOR_NUM_TABLE_CELLS = (NUM_TABLE_CELLS<2048) ? 8 : 0;
320 
321 
324  inline
325  void incrementPhase()
326  {
327  //phase_fractional += (phase_increment_fractional | 1); // odd phase incr, attempt to reduce frequency spurs in output
328  phase_fractional += phase_increment_fractional;
329  }
330 
331 
334  inline
335  int8_t readTable()
336  {
337 #ifdef OSCIL_DITHER_PHASE
338  return (int8_t)pgm_read_byte_near(table + (((phase_fractional + ((int)(xorshift96()>>16))) >> OSCIL_F_BITS) & (NUM_TABLE_CELLS - 1)));
339 #else
340  return (int8_t)pgm_read_byte_near(table + ((phase_fractional >> OSCIL_F_BITS) & (NUM_TABLE_CELLS - 1)));
341  //return (int8_t)pgm_read_byte_near(table + (((phase_fractional >> OSCIL_F_BITS) | 1 ) & (NUM_TABLE_CELLS - 1))); odd phase, attempt to reduce frequency spurs in output
342 #endif
343  }
344 
345 
346  unsigned long phase_fractional;
347  volatile unsigned long phase_increment_fractional; // volatile with atomic access because it can
348  // be set in the updateControl() interrupt and
349  // used in updateAudio(), which is outside the
350  // interrupt.
351  const int8_t * table;
352 
353 };
354 
355 
361 #endif /* OSCIL_H_ */
int8_t next()
Updates the phase according to the current frequency and returns the sample at the new phase position...
Definition: Oscil.h:93
int32_t Q15n16
signed fractional number using 15 integer bits and 16 fractional bits, represents -32767...
Definition: mozzi_fixmath.h:40
unsigned long getPhaseFractional()
Get the phase of the Oscil in fractional format.
Definition: Oscil.h:143
Oscil plays a wavetable, cycling through the table to generate an audio or control signal...
Definition: Oscil.h:65
const unsigned long phaseIncFromFreq(int frequency)
phaseIncFromFreq() and setPhaseInc() are for saving processor time when sliding between frequencies...
Definition: Oscil.h:291
void setFreq(int frequency)
Set the oscillator frequency with an unsigned int.
Definition: Oscil.h:179
void setPhaseFractional(unsigned long phase)
Set the phase of the Oscil.
Definition: Oscil.h:131
void setPhase(unsigned int phase)
Set the phase of the Oscil.
Definition: Oscil.h:116
int8_t phMod(Q15n16 phmod_proportion)
Returns the next sample given a phase modulation value.
Definition: Oscil.h:164
Oscil(const int8_t *TABLE_NAME)
Constructor.
Definition: Oscil.h:75
void setTable(const int8_t *TABLE_NAME)
Change the sound table which will be played by the Oscil.
Definition: Oscil.h:103
void setFreq(float frequency)
Set the oscillator frequency with a float.
Definition: Oscil.h:197
int8_t atIndex(unsigned int index)
Returns the sample at the given table index.
Definition: Oscil.h:273
unsigned long xorshift96()
Random number generator.
Definition: mozzi_rand.cpp:17
uint32_t Q24n8
unsigned fractional number using 24 integer bits and 8 fractional bits, represents 0 to 16777215 ...
Definition: mozzi_fixmath.h:45
void setFreq_Q16n16(Q16n16 frequency)
Set the frequency using Q16n16 fixed-point number format.
Definition: Oscil.h:244
void setPhaseInc(unsigned long phaseinc_fractional)
Set a specific phase increment.
Definition: Oscil.h:304
uint32_t Q16n16
unsigned fractional number using 16 integer bits and 16 fractional bits, represents 0 to 65535...
Definition: mozzi_fixmath.h:46
Oscil()
Constructor.
Definition: Oscil.h:85
void setFreq_Q24n8(Q24n8 frequency)
Set the frequency using Q24n8 fixed-point number format.
Definition: Oscil.h:214