Mozzi  version 2015-05-11-20:23
sound synthesis library for Arduino
 All Classes Functions Typedefs Groups
Sample.h
1 /*
2  * Sample.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 SAMPLE_H_
15 #define SAMPLE_H_
16 
17 #include "MozziGuts.h"
18 #include "mozzi_fixmath.h"
19 #include <util/atomic.h>
20 
21 // fractional bits for sample index precision
22 #define SAMPLE_F_BITS 16
23 #define SAMPLE_F_BITS_AS_MULTIPLIER 65536
24 
25 // phmod_proportion is an 1n15 fixed-point number only using
26 // the fractional part and the sign bit
27 #define SAMPLE_PHMOD_BITS 16
28 
29 enum interpolation {INTERP_NONE, INTERP_LINEAR};
30 
49 template <unsigned int NUM_TABLE_CELLS, unsigned int UPDATE_RATE, uint8_t INTERP=INTERP_NONE>
50 class Sample
51 {
52 
53 public:
54 
61  Sample(const int8_t * TABLE_NAME):table(TABLE_NAME),endpos_fractional((unsigned long) NUM_TABLE_CELLS << SAMPLE_F_BITS) // so isPlaying() will work
62  {
63  setLoopingOff();
64  //rangeWholeSample();
65  }
66 
67 
68 
73  Sample():endpos_fractional(4294967295UL) // biggest UL number so isPlaying() will work
74  {
75  setLoopingOff();
76  //rangeWholeSample();
77  }
78 
79 
83  inline
84  void setTable(const int8_t * TABLE_NAME)
85  {
86  table = TABLE_NAME;
87  }
88 
89 
93  inline
94  void setStart(unsigned int startpos)
95  {
96  startpos_fractional = (unsigned long) startpos << SAMPLE_F_BITS;
97  }
98 
99 
102  inline
103  void start()
104  {
105  // atomic because start() can be called on a sample in the control interrupt
106  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
107  {
108  phase_fractional = startpos_fractional;
109  }
110  }
111 
112 
116  inline
117  void start(unsigned int startpos)
118  {
119  setStart(startpos);
120  start();
121  }
122 
123 
127  inline
128  void setEnd(unsigned int end)
129  {
130  endpos_fractional = (unsigned long) end << SAMPLE_F_BITS;
131  }
132 
133 
136  inline
138  {
139  startpos_fractional = 0;
140  endpos_fractional = (unsigned long) NUM_TABLE_CELLS << SAMPLE_F_BITS;
141  }
142 
143 
146  inline
148  {
149  looping=true;
150  }
151 
152 
155  inline
157  {
158  looping=false;
159  }
160 
161 
162 
170  inline
171  int8_t next() { // 4us
172 
173  if (phase_fractional>endpos_fractional){
174  if (looping) {
175  phase_fractional = startpos_fractional + (phase_fractional - endpos_fractional);
176  }else{
177  return 0;
178  }
179  }
180  int8_t out;
181  if(INTERP==INTERP_LINEAR){
182  // WARNNG this is hard coded for when SAMPLE_F_BITS is 16
183  unsigned int index = phase_fractional >> SAMPLE_F_BITS;
184  out = (int8_t)pgm_read_byte_near(table + index);
185  int8_t difference = (int8_t)pgm_read_byte_near((table + 1) + index) - out;
186  int8_t diff_fraction = (int8_t)(((((unsigned int) phase_fractional)>>8)*difference)>>8); // (unsigned int) phase_fractional keeps low word, then>> for only 8 bit precision
187  out += diff_fraction;
188  }else{
189  out = (int8_t)pgm_read_byte_near(table + (phase_fractional >> SAMPLE_F_BITS));
190  }
191  incrementPhase();
192  return out;
193  }
194 
195 
199  inline
200  boolean isPlaying(){
201  return phase_fractional<endpos_fractional;
202  }
203 
204 
205  // Not readjusted for arbitrary table length yet
206  //
207  // Returns the next sample given a phase modulation value.
208  // @param phmod_proportion phase modulation value given as a proportion of the wave. The
209  // phmod_proportion parameter is a Q15n16 fixed-point number where to fractional
210  // n16 part represents -1 to 1, modulating the phase by one whole table length in
211  // each direction.
212  // @return a sample from the table.
213  //
214  // inline
215  // int8_t phMod(long phmod_proportion)
216  // {
217  // incrementPhase();
218  // return (int8_t)pgm_read_byte_near(table + (((phase_fractional+(phmod_proportion * NUM_TABLE_CELLS))>>SAMPLE_SAMPLE_F_BITS) & (NUM_TABLE_CELLS - 1)));
219  // }
220 
221 
222 
230  inline
231  void setFreq (int frequency) {
232  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
233  {
234  phase_increment_fractional = ((((unsigned long)NUM_TABLE_CELLS<<ADJUST_FOR_NUM_TABLE_CELLS)*frequency)/UPDATE_RATE) << (SAMPLE_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS);
235  }
236  }
237 
238 
244  inline
245  void setFreq(float frequency)
246  { // 1 us - using float doesn't seem to incur measurable overhead with the oscilloscope
247  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
248  {
249  phase_increment_fractional = (unsigned long)((((float)NUM_TABLE_CELLS * frequency)/UPDATE_RATE) * SAMPLE_F_BITS_AS_MULTIPLIER);
250  }
251  }
252 
253 
262  inline
263  void setFreq_Q24n8(Q24n8 frequency)
264  {
265  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
266  {
267  //phase_increment_fractional = (frequency* (NUM_TABLE_CELLS>>3)/(UPDATE_RATE>>6)) << (F_BITS-(8-3+6));
268  phase_increment_fractional = (((((unsigned long)NUM_TABLE_CELLS<<ADJUST_FOR_NUM_TABLE_CELLS)>>3)*frequency)/(UPDATE_RATE>>6))
269  << (SAMPLE_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS - (8-3+6));
270  }
271  }
272 
273 
278  inline
279  int8_t atIndex(unsigned int index)
280  {
281  return (int8_t)pgm_read_byte_near(table + index);
282  }
283 
284 
295  inline
296  unsigned long phaseIncFromFreq(unsigned int frequency)
297  {
298  return (((unsigned long)frequency * NUM_TABLE_CELLS)/UPDATE_RATE) << SAMPLE_F_BITS;
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 private:
316 
317 
320 static const uint8_t ADJUST_FOR_NUM_TABLE_CELLS = (NUM_TABLE_CELLS<2048) ? 8 : 0;
321 
322 
325  inline
326  void incrementPhase()
327  {
328  phase_fractional += phase_increment_fractional;
329  }
330 
331 
332  volatile unsigned long phase_fractional;
333  volatile unsigned long phase_increment_fractional;
334  const int8_t * table;
335  bool looping;
336  unsigned long startpos_fractional, endpos_fractional;
337 };
338 
339 
345 #endif /* SAMPLE_H_ */
void setFreq_Q24n8(Q24n8 frequency)
Set the frequency using Q24n8 fixed-point number format.
Definition: Sample.h:263
void setLoopingOn()
Turns looping on.
Definition: Sample.h:147
void setFreq(int frequency)
Set the oscillator frequency with an unsigned int.
Definition: Sample.h:231
void setEnd(unsigned int end)
Sets the end position in samples from the beginning of the sound.
Definition: Sample.h:128
Sample(const int8_t *TABLE_NAME)
Constructor.
Definition: Sample.h:61
void rangeWholeSample()
Sets the start and end points to include the range of the whole sound table.
Definition: Sample.h:137
unsigned long phaseIncFromFreq(unsigned int frequency)
phaseIncFromFreq() and setPhaseInc() are for saving processor time when sliding between frequencies...
Definition: Sample.h:296
int8_t atIndex(unsigned int index)
Returns the sample at the given table index.
Definition: Sample.h:279
void setPhaseInc(unsigned long phaseinc_fractional)
Set a specific phase increment.
Definition: Sample.h:306
void setStart(unsigned int startpos)
Sets the starting position in samples.
Definition: Sample.h:94
void start(unsigned int startpos)
Sets a new start position plays the sample from that position.
Definition: Sample.h:117
void setTable(const int8_t *TABLE_NAME)
Change the sound table which will be played by the Sample.
Definition: Sample.h:84
int8_t next()
Returns the sample at the current phase position, or 0 if looping is off and the phase overshoots the...
Definition: Sample.h:171
uint32_t Q24n8
unsigned fractional number using 24 integer bits and 8 fractional bits, represents 0 to 16777215 ...
Definition: mozzi_fixmath.h:45
boolean isPlaying()
Checks if the sample is playing by seeing if the phase is within the limits of its end position...
Definition: Sample.h:200
void start()
Resets the phase (the playhead) to the start position, which will be 0 unless set to another value wi...
Definition: Sample.h:103
void setFreq(float frequency)
Set the sample frequency with a float.
Definition: Sample.h:245
Sample is like Oscil, it plays a wavetable.
Definition: Sample.h:50
Sample()
Constructor.
Definition: Sample.h:73
void setLoopingOff()
Turns looping off.
Definition: Sample.h:156