Mozzi  version 2016-12-11-17:03
sound synthesis library for Arduino
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 // TB2016-10-2 line below might have been left in accidentally while making the 2014 change below, remove for now
221 // phase_increment_fractional = (((((unsigned long)NUM_TABLE_CELLS<<ADJUST_FOR_NUM_TABLE_CELLS)>>3)*frequency)/(UPDATE_RATE>>6))
222 // << (OSCIL_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS - (8-3+6));
223 
224  // TB2014-8-20 change this following Austin Grossman's suggestion on user list
225  // https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/mozzi-users/u4D5NMzVnQs/pCmiWInFvrkJ
226  if ((256UL*NUM_TABLE_CELLS) >= UPDATE_RATE) {
227  phase_increment_fractional = ((unsigned long)frequency) * ((256UL*NUM_TABLE_CELLS)/UPDATE_RATE);
228  } else {
229  phase_increment_fractional = ((unsigned long)frequency) / (UPDATE_RATE/(256UL*NUM_TABLE_CELLS));
230  }
231  }
232 
233 
234  }
235 
236 
245  inline
246  void setFreq_Q16n16(Q16n16 frequency)
247  {
248  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
249  {
250  //phase_increment_fractional = ((frequency * (NUM_TABLE_CELLS>>7))/(UPDATE_RATE>>6)) << (F_BITS-16+1);
251  // TB2014-8-20 change this following Austin Grossman's suggestion on user list
252  // https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/mozzi-users/u4D5NMzVnQs/pCmiWInFvrkJ
253  //phase_increment_fractional = (((((uint32_t)NUM_TABLE_CELLS<<ADJUST_FOR_NUM_TABLE_CELLS)>>7)*frequency)/(UPDATE_RATE>>6))
254  // << (OSCIL_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS - 16 + 1);
255  if (NUM_TABLE_CELLS >= UPDATE_RATE) {
256  phase_increment_fractional = ((unsigned long)frequency) * (NUM_TABLE_CELLS/UPDATE_RATE);
257  } else {
258  phase_increment_fractional = ((unsigned long)frequency) / (UPDATE_RATE/NUM_TABLE_CELLS);
259  }
260 
261  }
262  }
263 /*
264  inline
265  void setFreqMidi(int8_t note_num) {
266  setFreq_Q16n16(mtof(note_num));
267  }
268 */
274  inline
275  int8_t atIndex(unsigned int index)
276  {
277  return (int8_t)pgm_read_byte_near(table + (index & (NUM_TABLE_CELLS - 1)));
278  }
279 
280 
291  inline
292  const
293  unsigned long phaseIncFromFreq(int frequency)
294  {
295  // TB2014-8-20 change this following Austin Grossman's suggestion on user list
296  // https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/mozzi-users/u4D5NMzVnQs/pCmiWInFvrkJ
297  //return (((unsigned long)frequency * NUM_TABLE_CELLS)/UPDATE_RATE) << OSCIL_F_BITS;
298  return ((unsigned long)frequency) * ((OSCIL_F_BITS_AS_MULTIPLIER*NUM_TABLE_CELLS)/UPDATE_RATE);
299  }
300 
301 
305  inline
306  void setPhaseInc(unsigned long phaseinc_fractional)
307  {
308  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
309  {
310  phase_increment_fractional = phaseinc_fractional;
311  }
312  }
313 
314 
315 
316 private:
317 
318 
321 static const uint8_t ADJUST_FOR_NUM_TABLE_CELLS = (NUM_TABLE_CELLS<2048) ? 8 : 0;
322 
323 
326  inline
327  void incrementPhase()
328  {
329  //phase_fractional += (phase_increment_fractional | 1); // odd phase incr, attempt to reduce frequency spurs in output
330  phase_fractional += phase_increment_fractional;
331  }
332 
333 
336  inline
337  int8_t readTable()
338  {
339 #ifdef OSCIL_DITHER_PHASE
340  return (int8_t)pgm_read_byte_near(table + (((phase_fractional + ((int)(xorshift96()>>16))) >> OSCIL_F_BITS) & (NUM_TABLE_CELLS - 1)));
341 #else
342  return (int8_t)pgm_read_byte_near(table + ((phase_fractional >> OSCIL_F_BITS) & (NUM_TABLE_CELLS - 1)));
343  //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
344 #endif
345  }
346 
347 
348  unsigned long phase_fractional;
349  volatile unsigned long phase_increment_fractional; // volatile with atomic access because it can
350  // be set in the updateControl() interrupt and
351  // used in updateAudio(), which is outside the
352  // interrupt.
353  const int8_t * table;
354 
355 };
356 
357 
363 #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:293
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:275
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:246
void setPhaseInc(unsigned long phaseinc_fractional)
Set a specific phase increment.
Definition: Oscil.h:306
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