Added FM synthesis and corrected detune via MIDI

This commit is contained in:
Jakob Bak 2013-05-21 09:40:06 +02:00
parent 95b762afce
commit 5d2e9096c3

View File

@ -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) {