Mozzi  version v2.0
sound synthesis library for Arduino
Sample.h
1 /*
2  * Sample.h
3  *
4  * This file is part of Mozzi.
5  *
6  * Copyright 2012-2024 Tim Barrass and the Mozzi Team
7  *
8  * Mozzi is licensed under the GNU Lesser General Public Licence (LGPL) Version 2.1 or later.
9  *
10  */
11 
12 #ifndef SAMPLE_H_
13 #define SAMPLE_H_
14 
15 #include "MozziHeadersOnly.h"
16 #include "mozzi_fixmath.h"
17 #include "mozzi_pgmspace.h"
18 
19 // fractional bits for sample index precision
20 #define SAMPLE_F_BITS 16
21 #define SAMPLE_F_BITS_AS_MULTIPLIER 65536
22 
23 // phmod_proportion is an 1n15 fixed-point number only using
24 // the fractional part and the sign bit
25 #define SAMPLE_PHMOD_BITS 16
26 
27 enum interpolation {INTERP_NONE, INTERP_LINEAR};
28 
47 template <unsigned int NUM_TABLE_CELLS, unsigned int UPDATE_RATE, uint8_t INTERP=INTERP_NONE>
48 class Sample
49 {
50 
51 public:
52 
59  Sample(const int8_t * TABLE_NAME):table(TABLE_NAME),endpos_fractional((unsigned long) NUM_TABLE_CELLS << SAMPLE_F_BITS) // so isPlaying() will work
60  {
61  setLoopingOff();
62  //rangeWholeSample();
63  }
64 
65 
66 
71  Sample():endpos_fractional((unsigned long) NUM_TABLE_CELLS << SAMPLE_F_BITS)
72  {
73  setLoopingOff();
74  //rangeWholeSample();
75  }
76 
77 
81  inline
82  void setTable(const int8_t * TABLE_NAME)
83  {
84  table = TABLE_NAME;
85  }
86 
87 
91  inline
92  void setStart(unsigned int startpos)
93  {
94  startpos_fractional = (unsigned long) startpos << SAMPLE_F_BITS;
95  }
96 
97 
100  inline
101  void start()
102  {
103  phase_fractional = startpos_fractional;
104  }
105 
106 
110  inline
111  void start(unsigned int startpos)
112  {
113  setStart(startpos);
114  start();
115  }
116 
117 
121  inline
122  void setEnd(unsigned int end)
123  {
124  endpos_fractional = (unsigned long) end << SAMPLE_F_BITS;
125  }
126 
127 
130  inline
132  {
133  startpos_fractional = 0;
134  endpos_fractional = (unsigned long) NUM_TABLE_CELLS << SAMPLE_F_BITS;
135  }
136 
137 
140  inline
142  {
143  looping=true;
144  }
145 
146 
149  inline
151  {
152  looping=false;
153  }
154 
155 
156 
164  inline
165  int8_t next() { // 4us
166 
167  if (phase_fractional>endpos_fractional){
168  if (looping) {
169  phase_fractional = startpos_fractional + (phase_fractional - endpos_fractional);
170  }else{
171  return 0;
172  }
173  }
174  int8_t out;
175  if(INTERP==INTERP_LINEAR){
176  // WARNNG this is hard coded for when SAMPLE_F_BITS is 16
177  unsigned int index = phase_fractional >> SAMPLE_F_BITS;
178  out = FLASH_OR_RAM_READ<const int8_t>(table + index);
179  int8_t difference = FLASH_OR_RAM_READ<const int8_t>((table + 1) + index) - out;
180  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
181  out += diff_fraction;
182  }else{
183  out = FLASH_OR_RAM_READ<const int8_t>(table + (phase_fractional >> SAMPLE_F_BITS));
184  }
185  incrementPhase();
186  return out;
187  }
188 
189 
193  inline
194  boolean isPlaying(){
195  return phase_fractional<endpos_fractional;
196  }
197 
198 
199  // Not readjusted for arbitrary table length yet
200  //
201  // Returns the next sample given a phase modulation value.
202  // @param phmod_proportion phase modulation value given as a proportion of the wave. The
203  // phmod_proportion parameter is a Q15n16 fixed-point number where to fractional
204  // n16 part represents -1 to 1, modulating the phase by one whole table length in
205  // each direction.
206  // @return a sample from the table.
207  //
208  // inline
209  // int8_t phMod(long phmod_proportion)
210  // {
211  // incrementPhase();
212  // return FLASH_OR_RAM_READ<const int8_t>(table + (((phase_fractional+(phmod_proportion * NUM_TABLE_CELLS))>>SAMPLE_SAMPLE_F_BITS) & (NUM_TABLE_CELLS - 1)));
213  // }
214 
215 
216 
224  inline
225  void setFreq (int frequency) {
226  phase_increment_fractional = ((((unsigned long)NUM_TABLE_CELLS<<ADJUST_FOR_NUM_TABLE_CELLS)*frequency)/UPDATE_RATE) << (SAMPLE_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS);
227  }
228 
229 
235  inline
236  void setFreq(float frequency)
237  { // 1 us - using float doesn't seem to incur measurable overhead with the oscilloscope
238  phase_increment_fractional = (unsigned long)((((float)NUM_TABLE_CELLS * frequency)/UPDATE_RATE) * SAMPLE_F_BITS_AS_MULTIPLIER);
239  }
240 
241 
250  inline
251  void setFreq_Q24n8(Q24n8 frequency)
252  {
253  //phase_increment_fractional = (frequency* (NUM_TABLE_CELLS>>3)/(UPDATE_RATE>>6)) << (F_BITS-(8-3+6));
254  phase_increment_fractional = (((((unsigned long)NUM_TABLE_CELLS<<ADJUST_FOR_NUM_TABLE_CELLS)>>3)*frequency)/(UPDATE_RATE>>6))
255  << (SAMPLE_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS - (8-3+6));
256  }
257 
258 
263  inline
264  int8_t atIndex(unsigned int index)
265  {
266  return FLASH_OR_RAM_READ<const int8_t>(table + index);
267  }
268 
269 
280  inline
281  unsigned long phaseIncFromFreq(unsigned int frequency)
282  {
283  return (((unsigned long)frequency * NUM_TABLE_CELLS)/UPDATE_RATE) << SAMPLE_F_BITS;
284  }
285 
286 
290  inline
291  void setPhaseInc(unsigned long phaseinc_fractional)
292  {
293  phase_increment_fractional = phaseinc_fractional;
294  }
295 
296 
297 private:
298 
299 
302 static const uint8_t ADJUST_FOR_NUM_TABLE_CELLS = (NUM_TABLE_CELLS<2048) ? 8 : 0;
303 
304 
307  inline
308  void incrementPhase()
309  {
310  phase_fractional += phase_increment_fractional;
311  }
312 
313 
314  volatile unsigned long phase_fractional;
315  volatile unsigned long phase_increment_fractional;
316  const int8_t * table;
317  bool looping;
318  unsigned long startpos_fractional, endpos_fractional;
319 };
320 
321 
327 #endif /* SAMPLE_H_ */
This file provides declarations of the Mozzi Core Functions Mozzi functions, but no implementation.
Sample is like Oscil, it plays a wavetable.
Definition: Sample.h:49
void setStart(unsigned int startpos)
Sets the starting position in samples.
Definition: Sample.h:92
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:165
Sample(const int8_t *TABLE_NAME)
Constructor.
Definition: Sample.h:59
unsigned long phaseIncFromFreq(unsigned int frequency)
phaseIncFromFreq() and setPhaseInc() are for saving processor time when sliding between frequencies.
Definition: Sample.h:281
void setLoopingOn()
Turns looping on.
Definition: Sample.h:141
void start()
Resets the phase (the playhead) to the start position, which will be 0 unless set to another value wi...
Definition: Sample.h:101
void setFreq(float frequency)
Set the sample frequency with a float.
Definition: Sample.h:236
int8_t atIndex(unsigned int index)
Returns the sample at the given table index.
Definition: Sample.h:264
void rangeWholeSample()
Sets the start and end points to include the range of the whole sound table.
Definition: Sample.h:131
void setFreq_Q24n8(Q24n8 frequency)
Set the frequency using Q24n8 fixed-point number format.
Definition: Sample.h:251
void setEnd(unsigned int end)
Sets the end position in samples from the beginning of the sound.
Definition: Sample.h:122
void setFreq(int frequency)
Set the oscillator frequency with an unsigned int.
Definition: Sample.h:225
void setPhaseInc(unsigned long phaseinc_fractional)
Set a specific phase increment.
Definition: Sample.h:291
void start(unsigned int startpos)
Sets a new start position plays the sample from that position.
Definition: Sample.h:111
Sample()
Constructor.
Definition: Sample.h:71
void setLoopingOff()
Turns looping off.
Definition: Sample.h:150
void setTable(const int8_t *TABLE_NAME)
Change the sound table which will be played by the Sample.
Definition: Sample.h:82
boolean isPlaying()
Checks if the sample is playing by seeing if the phase is within the limits of its end position.
Definition: Sample.h:194
uint32_t Q24n8
unsigned fractional number using 24 integer bits and 8 fractional bits, represents 0 to 16777215
Definition: mozzi_fixmath.h:51