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 
102  inline
103  void start()
104  {
105  phase_fractional = startpos_fractional;
106  if(paused) setPaused(false);
107  }
108 
109 
113  inline
114  void start(unsigned int startpos)
115  {
116  setStart(startpos);
117  start();
118  }
119 
124  inline
125  void setPaused(bool to_pause = true)
126  {
127  paused = to_pause;
128  }
129 
131  inline
132  bool isPaused() const { return paused; }
133 
134 
138  inline
139  void setEnd(unsigned int end)
140  {
141  endpos_fractional = (unsigned long) end << SAMPLE_F_BITS;
142  }
143 
144 
147  inline
149  {
150  startpos_fractional = 0;
151  endpos_fractional = (unsigned long) NUM_TABLE_CELLS << SAMPLE_F_BITS;
152  }
153 
154 
157  inline
159  {
160  looping=true;
161  }
162 
163 
166  inline
168  {
169  looping=false;
170  }
171 
172 
173 
181  inline
182  int8_t next() { // 4us
183 
184  if (paused) return 0;
185  if (phase_fractional>=endpos_fractional){
186  if (looping) {
187  phase_fractional = startpos_fractional + (phase_fractional - endpos_fractional);
188  }else{
189  return 0;
190  }
191  }
192  int8_t out;
193  if(INTERP==INTERP_LINEAR){
194  // WARNNG this is hard coded for when SAMPLE_F_BITS is 16
195  unsigned int index = phase_fractional >> SAMPLE_F_BITS;
196  out = FLASH_OR_RAM_READ<const int8_t>(table + index);
197  int8_t difference = FLASH_OR_RAM_READ<const int8_t>((table + 1) + index) - out;
198  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
199  out += diff_fraction;
200  }else{
201  out = FLASH_OR_RAM_READ<const int8_t>(table + (phase_fractional >> SAMPLE_F_BITS));
202  }
203  incrementPhase();
204  return out;
205  }
206 
207 
211  inline
212  boolean isPlaying(){
213  return phase_fractional<endpos_fractional && !paused;
214  }
215 
216 
217  // Not readjusted for arbitrary table length yet
218  //
219  // Returns the next sample given a phase modulation value.
220  // @param phmod_proportion phase modulation value given as a proportion of the wave. The
221  // phmod_proportion parameter is a Q15n16 fixed-point number where to fractional
222  // n16 part represents -1 to 1, modulating the phase by one whole table length in
223  // each direction.
224  // @return a sample from the table.
225  //
226  // inline
227  // int8_t phMod(long phmod_proportion)
228  // {
229  // incrementPhase();
230  // return FLASH_OR_RAM_READ<const int8_t>(table + (((phase_fractional+(phmod_proportion * NUM_TABLE_CELLS))>>SAMPLE_SAMPLE_F_BITS) & (NUM_TABLE_CELLS - 1)));
231  // }
232 
233 
234 
242  inline
243  void setFreq (int frequency) {
244  phase_increment_fractional = ((((unsigned long)NUM_TABLE_CELLS<<ADJUST_FOR_NUM_TABLE_CELLS)*frequency)/UPDATE_RATE) << (SAMPLE_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS);
245  }
246 
247 
253  inline
254  void setFreq(float frequency)
255  { // 1 us - using float doesn't seem to incur measurable overhead with the oscilloscope
256  phase_increment_fractional = (unsigned long)((((float)NUM_TABLE_CELLS * frequency)/UPDATE_RATE) * SAMPLE_F_BITS_AS_MULTIPLIER);
257  }
258 
259 
268  inline
269  void setFreq_Q24n8(Q24n8 frequency)
270  {
271  //phase_increment_fractional = (frequency* (NUM_TABLE_CELLS>>3)/(UPDATE_RATE>>6)) << (F_BITS-(8-3+6));
272  phase_increment_fractional = (((((unsigned long)NUM_TABLE_CELLS<<ADJUST_FOR_NUM_TABLE_CELLS)>>3)*frequency)/(UPDATE_RATE>>6))
273  << (SAMPLE_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS - (8-3+6));
274  }
275 
276 
281  inline
282  int8_t atIndex(unsigned int index)
283  {
284  return FLASH_OR_RAM_READ<const int8_t>(table + index);
285  }
286 
287 
298  inline
299  unsigned long phaseIncFromFreq(unsigned int frequency)
300  {
301  return (((unsigned long)frequency * NUM_TABLE_CELLS)/UPDATE_RATE) << SAMPLE_F_BITS;
302  }
303 
304 
308  inline
309  void setPhaseInc(unsigned long phaseinc_fractional)
310  {
311  phase_increment_fractional = phaseinc_fractional;
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  bool paused{false};
337  unsigned long startpos_fractional, endpos_fractional;
338 };
339 
340 
346 #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:182
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:299
void setLoopingOn()
Turns looping on.
Definition: Sample.h:158
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:254
int8_t atIndex(unsigned int index)
Returns the sample at the given table index.
Definition: Sample.h:282
void rangeWholeSample()
Sets the start and end points to include the range of the whole sound table.
Definition: Sample.h:148
void setFreq_Q24n8(Q24n8 frequency)
Set the frequency using Q24n8 fixed-point number format.
Definition: Sample.h:269
void setEnd(unsigned int end)
Sets the end position in samples from the beginning of the sound.
Definition: Sample.h:139
bool isPaused() const
Checks whether playback is paused.
Definition: Sample.h:132
void setFreq(int frequency)
Set the oscillator frequency with an unsigned int.
Definition: Sample.h:243
void setPhaseInc(unsigned long phaseinc_fractional)
Set a specific phase increment.
Definition: Sample.h:309
void setPaused(bool to_pause=true)
Puts playback of the sample on pause or unpauses it.
Definition: Sample.h:125
void start(unsigned int startpos)
Sets a new start position plays the sample from that position.
Definition: Sample.h:114
Sample()
Constructor.
Definition: Sample.h:71
void setLoopingOff()
Turns looping off.
Definition: Sample.h:167
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:212
uint32_t Q24n8
unsigned fractional number using 24 integer bits and 8 fractional bits, represents 0 to 16777215
Definition: mozzi_fixmath.h:51