|
#ifndef SAMPLE16_H_ |
|
#define SAMPLE16_H_ |
|
|
|
#include "MozziHeadersOnly.h" |
|
#include "mozzi_fixmath.h" |
|
#include "mozzi_pgmspace.h" |
|
|
|
#define SAMPLE16_F_BITS 16 |
|
#define SAMPLE16_F_BITS_AS_MULTIPLIER 65536 |
|
|
|
enum interpolation16 |
|
{ |
|
INTERP16_NONE, |
|
INTERP16_LINEAR |
|
}; |
|
|
|
template <unsigned int NUM_TABLE_CELLS, unsigned int UPDATE_RATE, uint8_t INTERP = INTERP16_NONE> |
|
class Sample16 |
|
{ |
|
public: |
|
Sample16(const int16_t* TABLE_NAME) : table(TABLE_NAME), endpos_fractional((uint64_t)NUM_TABLE_CELLS << SAMPLE16_F_BITS) |
|
{ |
|
setLoopingOff(); |
|
} |
|
|
|
Sample16() : endpos_fractional((uint64_t)NUM_TABLE_CELLS << SAMPLE16_F_BITS) |
|
{ |
|
setLoopingOff(); |
|
} |
|
|
|
inline void setTable(const int16_t* TABLE_NAME) |
|
{ |
|
table = TABLE_NAME; |
|
} |
|
|
|
inline void setStart(unsigned int startpos) |
|
{ |
|
startpos_fractional = (uint64_t)startpos << SAMPLE16_F_BITS; |
|
} |
|
|
|
inline void start() |
|
{ |
|
phase_fractional = startpos_fractional; |
|
} |
|
|
|
inline void start(unsigned int startpos) |
|
{ |
|
setStart(startpos); |
|
start(); |
|
} |
|
|
|
inline void setEnd(unsigned int end) |
|
{ |
|
endpos_fractional = (uint64_t)end << SAMPLE16_F_BITS; |
|
} |
|
|
|
inline void rangeWholeSample() |
|
{ |
|
startpos_fractional = 0; |
|
endpos_fractional = (uint64_t)NUM_TABLE_CELLS << SAMPLE16_F_BITS; |
|
} |
|
|
|
inline void setLoopingOn() |
|
{ |
|
looping = true; |
|
} |
|
|
|
inline void setLoopingOff() |
|
{ |
|
looping = false; |
|
} |
|
|
|
inline int16_t next() |
|
{ |
|
if (phase_fractional > endpos_fractional) { |
|
if (looping) { |
|
phase_fractional = startpos_fractional + (phase_fractional - endpos_fractional); |
|
} else { |
|
return 0; |
|
} |
|
} |
|
int16_t out; |
|
if (INTERP == INTERP16_LINEAR) { |
|
unsigned int index = phase_fractional >> SAMPLE16_F_BITS; |
|
out = FLASH_OR_RAM_READ<const int16_t>(table + index); |
|
int16_t difference = FLASH_OR_RAM_READ<const int16_t>((table + 1) + index) - out; |
|
int16_t diff_fraction = (int16_t)(((((unsigned int)phase_fractional) >> 8) * difference) >> 8); |
|
out += diff_fraction; |
|
} else { |
|
out = FLASH_OR_RAM_READ<const int16_t>(table + (phase_fractional >> SAMPLE16_F_BITS)); |
|
} |
|
incrementPhase(); |
|
return out; |
|
} |
|
|
|
inline boolean isPlaying() |
|
{ |
|
return phase_fractional < endpos_fractional; |
|
} |
|
|
|
inline void setFreq(int frequency) |
|
{ |
|
phase_increment_fractional = ((((uint64_t)NUM_TABLE_CELLS << ADJUST_FOR_NUM_TABLE_CELLS) * frequency) / UPDATE_RATE) << (SAMPLE16_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS); |
|
} |
|
|
|
inline void setFreq(float frequency) |
|
{ |
|
phase_increment_fractional = (uint64_t)((((float)NUM_TABLE_CELLS * frequency) / UPDATE_RATE) * SAMPLE16_F_BITS_AS_MULTIPLIER); |
|
} |
|
|
|
inline void setFreq_Q24n8(Q24n8 frequency) |
|
{ |
|
phase_increment_fractional = (((((uint64_t)NUM_TABLE_CELLS << ADJUST_FOR_NUM_TABLE_CELLS) >> 3) * frequency) / (UPDATE_RATE >> 6)) << (SAMPLE16_F_BITS - ADJUST_FOR_NUM_TABLE_CELLS - (8 - 3 + 6)); |
|
} |
|
|
|
inline int16_t atIndex(unsigned int index) |
|
{ |
|
return FLASH_OR_RAM_READ<const int16_t>(table + index); |
|
} |
|
|
|
inline uint64_t phaseIncFromFreq(unsigned int frequency) |
|
{ |
|
return (((uint64_t)frequency * NUM_TABLE_CELLS) / UPDATE_RATE) << SAMPLE16_F_BITS; |
|
} |
|
|
|
inline void setPhaseInc(uint64_t phaseinc_fractional) |
|
{ |
|
phase_increment_fractional = phaseinc_fractional; |
|
} |
|
|
|
private: |
|
static const uint8_t ADJUST_FOR_NUM_TABLE_CELLS = (NUM_TABLE_CELLS < 2048) ? 8 : 0; |
|
|
|
inline void incrementPhase() |
|
{ |
|
phase_fractional += phase_increment_fractional; |
|
} |
|
|
|
volatile uint64_t phase_fractional; |
|
volatile uint64_t phase_increment_fractional; |
|
const int16_t* table; |
|
bool looping; |
|
uint64_t startpos_fractional, endpos_fractional; |
|
}; |
|
|
|
#endif |