Added FM synthesis and corrected detune via MIDI
This commit is contained in:
parent
95b762afce
commit
5d2e9096c3
@ -42,7 +42,7 @@
|
|||||||
#define SPI_SCK 5
|
#define SPI_SCK 5
|
||||||
#define SPI_MOSI 3
|
#define SPI_MOSI 3
|
||||||
|
|
||||||
// Checking of NUM_OSCILLATORS is set, and if not, default to 1 oscillator
|
// Checking if NUM_OSCILLATORS is set, and if not, default to 1 oscillator
|
||||||
#ifndef NUM_OSCILLATORS
|
#ifndef NUM_OSCILLATORS
|
||||||
#define NUM_OSCILLATORS 1
|
#define NUM_OSCILLATORS 1
|
||||||
#elif (NUM_OSCILLATORS == 1)||(NUM_OSCILLATORS == 2)||(NUM_OSCILLATORS == 3)
|
#elif (NUM_OSCILLATORS == 1)||(NUM_OSCILLATORS == 2)||(NUM_OSCILLATORS == 3)
|
||||||
@ -50,7 +50,7 @@
|
|||||||
#error NUM_OSCILLATORS shall be 1, 2 or 3
|
#error NUM_OSCILLATORS shall be 1, 2 or 3
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Checking of BIT_DEPTH is set, and if not, default to 8bit
|
// Checking if BIT_DEPTH is set, and if not, default to 8bit
|
||||||
#ifndef BIT_DEPTH
|
#ifndef BIT_DEPTH
|
||||||
#define BIT_DEPTH 8
|
#define BIT_DEPTH 8
|
||||||
#elif (BIT_DEPTH == 8)||(BIT_DEPTH == 12)
|
#elif (BIT_DEPTH == 8)||(BIT_DEPTH == 12)
|
||||||
@ -58,6 +58,7 @@
|
|||||||
#error BIT_DEPTH shall be 8 or 12
|
#error BIT_DEPTH shall be 8 or 12
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Shortnames for waveforms
|
// Shortnames for waveforms
|
||||||
#define SINE 0
|
#define SINE 0
|
||||||
#define SQUARE 1
|
#define SQUARE 1
|
||||||
@ -141,7 +142,9 @@ public:
|
|||||||
|
|
||||||
// AUDIO INTERRUPT SERVICE ROUTINE
|
// AUDIO INTERRUPT SERVICE ROUTINE
|
||||||
void synthInterrupt8bit();
|
void synthInterrupt8bit();
|
||||||
|
void synthInterrupt8bitFM();
|
||||||
void synthInterrupt12bitSine();
|
void synthInterrupt12bitSine();
|
||||||
|
void synthInterrupt12bitSineFM();
|
||||||
|
|
||||||
// FREQUENCY AND DETUNE FUNCTIONS
|
// FREQUENCY AND DETUNE FUNCTIONS
|
||||||
void setFrequency(float frequency);
|
void setFrequency(float frequency);
|
||||||
@ -155,6 +158,9 @@ public:
|
|||||||
void setDetune1(float detune);
|
void setDetune1(float detune);
|
||||||
void setDetune2(float detune);
|
void setDetune2(float detune);
|
||||||
void setDetune3(float detune);
|
void setDetune3(float detune);
|
||||||
|
void setFM1(uint8_t fm);
|
||||||
|
void setFM2(uint8_t fm);
|
||||||
|
void setFM3(uint8_t fm);
|
||||||
void pitchBend(float b); // NOT IMPLEMENTED
|
void pitchBend(float b); // NOT IMPLEMENTED
|
||||||
|
|
||||||
// WAVEFORM FUNCTIONS
|
// WAVEFORM FUNCTIONS
|
||||||
@ -233,6 +239,12 @@ private:
|
|||||||
uint32_t oscil1;
|
uint32_t oscil1;
|
||||||
uint32_t oscil2;
|
uint32_t oscil2;
|
||||||
uint32_t oscil3;
|
uint32_t oscil3;
|
||||||
|
int32_t modulator1;
|
||||||
|
int32_t modulator2;
|
||||||
|
int32_t modulator3;
|
||||||
|
int8_t fmAmount1;
|
||||||
|
int8_t fmAmount2;
|
||||||
|
int8_t fmAmount3;
|
||||||
uint16_t gain;
|
uint16_t gain;
|
||||||
uint16_t gain1;
|
uint16_t gain1;
|
||||||
uint16_t gain2;
|
uint16_t gain2;
|
||||||
@ -313,14 +325,18 @@ ISR(TIMER2_COMPA_vect) { // timer 2 is audio interrupt timer
|
|||||||
OCR2A = 127; // don't change this
|
OCR2A = 127; // don't change this
|
||||||
|
|
||||||
#if BIT_DEPTH == 8
|
#if BIT_DEPTH == 8
|
||||||
|
#ifdef FM
|
||||||
Music.synthInterrupt8bit();
|
Music.synthInterrupt8bitFM();
|
||||||
|
#else
|
||||||
|
Music.synthInterrupt8bit();
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if BIT_DEPTH == 12
|
#if BIT_DEPTH == 12
|
||||||
|
#ifdef FM
|
||||||
Music.synthInterrupt12bitSine();
|
Music.synthInterrupt12bitSineFM();
|
||||||
|
#else
|
||||||
|
Music.synthInterrupt12bitSine();
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -451,6 +467,118 @@ void inline MMusic::synthInterrupt8bit()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 8 BIT WAVETABLE - AUDIO INTERRUPT SERVICE ROUTINE
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
void inline MMusic::synthInterrupt8bitFM ()
|
||||||
|
{
|
||||||
|
|
||||||
|
PORTD &= ~(1<<3);
|
||||||
|
|
||||||
|
// Frame sync low for SPI (making it low here so that we can measure lenght of interrupt with scope)
|
||||||
|
#ifdef CFO
|
||||||
|
PORTB &= ~(1<<2);
|
||||||
|
#else
|
||||||
|
PORTD &= ~(1<<6);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
accumulator1 = accumulator1 + period1;
|
||||||
|
index1 = accumulator1 >> 8;
|
||||||
|
//oscil1 = 0;
|
||||||
|
memcpy_P(&oscil1, &waveTable[index1 + waveForm1],1);
|
||||||
|
//sample = (oscil1 * gain1);
|
||||||
|
|
||||||
|
//modulator2 = 0;
|
||||||
|
modulator2 = (fmAmount2 * (oscil1-128) * int32_t(period2))>>14;
|
||||||
|
//modulator2 = (period2 * (oscil1-128))>>7;
|
||||||
|
accumulator2 = accumulator2 + period2 + modulator2;
|
||||||
|
index2 = accumulator2 >> 8;
|
||||||
|
//oscil2 = 0;
|
||||||
|
memcpy_P(&oscil2, &waveTable[index2 + waveForm2],1);
|
||||||
|
sample = (oscil2 * gain2);
|
||||||
|
|
||||||
|
sample >>= 8;
|
||||||
|
|
||||||
|
|
||||||
|
// AMPLIFICATION ENVELOPE
|
||||||
|
// Amplification envelope is calculated here
|
||||||
|
if(envelopeOn) {
|
||||||
|
|
||||||
|
// Attack
|
||||||
|
if(envStage == 1) {
|
||||||
|
env += attack;
|
||||||
|
if(velPeak < env) {
|
||||||
|
env = velPeak;
|
||||||
|
envStage = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Decay
|
||||||
|
else if(envStage == 2) {
|
||||||
|
env -= decay;
|
||||||
|
if(env < velSustain || MAX_ENV_GAIN < env) {
|
||||||
|
env = velSustain;
|
||||||
|
envStage = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Sustain
|
||||||
|
else if (envStage == 3) {
|
||||||
|
env = velSustain;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release
|
||||||
|
else if (envStage == 4) {
|
||||||
|
env -= release;
|
||||||
|
if(MAX_ENV_GAIN < env) {
|
||||||
|
env = 0;
|
||||||
|
envStage = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
// No gain
|
||||||
|
else if (envStage == 0) {
|
||||||
|
env = 0;
|
||||||
|
//accumulator1 = 0;
|
||||||
|
//accumulator2 = 0;
|
||||||
|
//accumulator3 = 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
env = 65535;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adding the amplification envelope (16bit) we bring it back to the 16bit frame again afterwards.
|
||||||
|
sample = (env * sample) >> 16;
|
||||||
|
|
||||||
|
|
||||||
|
// Formatting the samples to be transfered to the MCP4921 DAC
|
||||||
|
dacSPI0 = sample >> 8;
|
||||||
|
dacSPI0 >>= 4;
|
||||||
|
dacSPI0 |= 0x30;
|
||||||
|
dacSPI1 = sample >> 4;
|
||||||
|
|
||||||
|
SPCR |= (1 << MSTR);
|
||||||
|
|
||||||
|
// transmit value out the SPI port
|
||||||
|
SPDR = dacSPI0;
|
||||||
|
while (!(SPSR & (1<<SPIF))); // Maybe this can be optimised
|
||||||
|
SPDR = dacSPI1;
|
||||||
|
while (!(SPSR & (1<<SPIF))); // Maybe this can be optimised
|
||||||
|
|
||||||
|
// Frame sync high
|
||||||
|
#ifdef CFO
|
||||||
|
PORTB |= (1<<2);
|
||||||
|
#else
|
||||||
|
PORTD |= (1<<6);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// 12 BIT SINEWAVE - AUDIO INTERRUPT SERVICE ROUTINE
|
// 12 BIT SINEWAVE - AUDIO INTERRUPT SERVICE ROUTINE
|
||||||
@ -569,6 +697,115 @@ void MMusic::synthInterrupt12bitSine()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 12 BIT SINEWAVE - AUDIO INTERRUPT SERVICE ROUTINE
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
void MMusic::synthInterrupt12bitSineFM()
|
||||||
|
{
|
||||||
|
// Frame sync low for SPI (making it low here so that we can measure lenght of interrupt with scope)
|
||||||
|
#ifdef CFO
|
||||||
|
PORTB &= ~(1<<2);
|
||||||
|
#else
|
||||||
|
PORTD &= ~(1<<6);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
accumulator1 = accumulator1 + period1;
|
||||||
|
index1 = accumulator1 >> 4;
|
||||||
|
memcpy_P(&oscil1, &sineTable[index1],2);
|
||||||
|
//sample = (oscil1 * gain1) << 2;
|
||||||
|
|
||||||
|
//modulator2 = 0;
|
||||||
|
modulator2 = (fmAmount2 * int32_t(oscil1-2048))>>2;
|
||||||
|
modulator2 = (modulator2 * int32_t(period2))>>16;
|
||||||
|
accumulator2 = accumulator2 + period2 + modulator2;
|
||||||
|
//accumulator2 = accumulator2 + period2;
|
||||||
|
index2 = accumulator2 >> 4;
|
||||||
|
memcpy_P(&oscil2, &sineTable[index2],2);
|
||||||
|
sample = (oscil2 * gain2);
|
||||||
|
sample >>= 12;
|
||||||
|
|
||||||
|
|
||||||
|
// AMPLIFICATION ENVELOPE
|
||||||
|
// Amplification envelope is calculated here
|
||||||
|
if(envelopeOn) {
|
||||||
|
|
||||||
|
// Attack
|
||||||
|
if(envStage == 1) {
|
||||||
|
env += attack;
|
||||||
|
if(velPeak < env) {
|
||||||
|
env = velPeak;
|
||||||
|
envStage = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Decay
|
||||||
|
else if(envStage == 2) {
|
||||||
|
env -= decay;
|
||||||
|
if(env < velSustain || MAX_ENV_GAIN < env) {
|
||||||
|
env = velSustain;
|
||||||
|
envStage = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Sustain
|
||||||
|
else if (envStage == 3) {
|
||||||
|
env = velSustain;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release
|
||||||
|
else if (envStage == 4) {
|
||||||
|
env -= release;
|
||||||
|
if(MAX_ENV_GAIN < env) {
|
||||||
|
env = 0;
|
||||||
|
envStage = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
// No gain
|
||||||
|
else if (envStage == 0) {
|
||||||
|
env = 0;
|
||||||
|
//accumulator1 = 0;
|
||||||
|
//accumulator2 = 0;
|
||||||
|
//accumulator3 = 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
env = 65535;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adding the amplification envelope (16bit) we bring it back to the 16bit frame again afterwards.
|
||||||
|
sample = (env * sample) >> 16;
|
||||||
|
|
||||||
|
// Formatting the samples to be transfered to the MCP4921 DAC
|
||||||
|
dacSPI0 = sample >> 8;
|
||||||
|
dacSPI0 >>= 4;
|
||||||
|
dacSPI0 |= 0x30;
|
||||||
|
dacSPI1 = sample >> 4;
|
||||||
|
|
||||||
|
SPCR |= (1 << MSTR);
|
||||||
|
|
||||||
|
// transmit value out the SPI port
|
||||||
|
SPDR = dacSPI0;
|
||||||
|
while (!(SPSR & (1<<SPIF))); // Maybe this can be optimised
|
||||||
|
SPDR = dacSPI1;
|
||||||
|
while (!(SPSR & (1<<SPIF))); // Maybe this can be optimised
|
||||||
|
|
||||||
|
// Frame sync high
|
||||||
|
#ifdef CFO
|
||||||
|
PORTB |= (1<<2);
|
||||||
|
#else
|
||||||
|
PORTD |= (1<<6);
|
||||||
|
#endif
|
||||||
|
// Frame sync high
|
||||||
|
PORTD |= (1<<3);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MMusic Music;
|
MMusic Music;
|
||||||
|
|
||||||
#ifdef MIDI
|
#ifdef MIDI
|
||||||
@ -645,6 +882,9 @@ void MMusic::init()
|
|||||||
setRelease(64);
|
setRelease(64);
|
||||||
setVelSustain(0);
|
setVelSustain(0);
|
||||||
|
|
||||||
|
setFM2(0);
|
||||||
|
setFM3(0);
|
||||||
|
|
||||||
//sei(); // global interrupt enable
|
//sei(); // global interrupt enable
|
||||||
|
|
||||||
//Serial.println("MUSIC INITIALIZED!");
|
//Serial.println("MUSIC INITIALIZED!");
|
||||||
@ -771,6 +1011,21 @@ void MMusic::pitchBend(float b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MMusic::setFM1(uint8_t fm) {
|
||||||
|
fmAmount1 = fm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MMusic::setFM2(uint8_t fm) {
|
||||||
|
fmAmount2 = fm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MMusic::setFM3(uint8_t fm) {
|
||||||
|
fmAmount3 = fm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
@ -1136,13 +1391,17 @@ void MMidi::controller(uint8_t channel, uint8_t number, uint8_t value) {
|
|||||||
Music.setFrequency3(Music.getNoteFrequency(value));
|
Music.setFrequency3(Music.getNoteFrequency(value));
|
||||||
break;
|
break;
|
||||||
case DETUNE1:
|
case DETUNE1:
|
||||||
Music.setDetune1(value/5120.0);
|
Music.setDetune1(map(value,0,127,-100,100)*0.0005946);
|
||||||
break;
|
break;
|
||||||
case DETUNE2:
|
case DETUNE2:
|
||||||
Music.setDetune2(value/5120.0);
|
Music.setDetune2(map(value,0,127,-100,100)*0.0005946);
|
||||||
|
//Music.setDetune2((value-64.0)*0.0005946);
|
||||||
|
//Music.setDetune2(value/5120.0);
|
||||||
break;
|
break;
|
||||||
case DETUNE3:
|
case DETUNE3:
|
||||||
Music.setDetune3(value/5120.0);
|
Music.setDetune3(map(value,0,127,-100,100)*0.0005946);
|
||||||
|
//Music.setDetune3((value-64.0)*0.0005946);
|
||||||
|
//Music.setDetune3(value/5120.0);
|
||||||
break;
|
break;
|
||||||
case SEMITONE1:
|
case SEMITONE1:
|
||||||
if(15 < value && value < 113) {
|
if(15 < value && value < 113) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user