diff --git a/software/apps/Motion/Center_with_2_oscillators/Center_with_2_oscillators.ino b/software/apps/Motion/Center_with_2_oscillators/Center_with_2_oscillators.ino index 530ef9a..c85b09b 100644 --- a/software/apps/Motion/Center_with_2_oscillators/Center_with_2_oscillators.ino +++ b/software/apps/Motion/Center_with_2_oscillators/Center_with_2_oscillators.ino @@ -1,30 +1,25 @@ -//Center +//Center two motors control two frequencies. (jb&bv 25Jan13) //uses a variable force (pwm duty) //If it feels like a mountain - pushing away from center, then -//reverse the motor leads +//reverse the motor leads or the sign of forceA or forceB //or for a quick fix in the code: change if(f < 0) to if (f > 0) -//#define NUM_OSCILLATORS 3 -//#include "config.h" -#include -#include -#include +// notes to me (bv) +#include "Motor.h" +#include "Music.h" int posA, posB; // position from analogRead int forceA, forceB; // computed from pos and k -int kA = -5; // spring constant -int kB = 1; // spring constant +int kA = 2; // spring constant +int kB = 2; // spring constant //int duty; // pwm duty for Timer1 (range 0 - 1023) 10-bit resolution void setup() { MotorA.init(); - Music.init(); - Music.setWaveform(1); // only works with 8bit waveforms - //Music.setGain2(0); - //Music.setGain3(0); - Midi.init(); + Music.init(); // 12-bit sine default (see .cpp file) + //Music.setWaveform(0); // only works with 8bit waveforms } void loop() @@ -35,18 +30,12 @@ void loop() Music.setFrequency1(posA); Music.setFrequency2(posB); - //Music.setDetune((posB/8)/5120.0); - forceA = kA * (512 - posA); + forceA = - kA * (512 - posA); // check wiring??? forceB = kB * (512 - posB); - //duty = abs(force); - //duty = min(512, duty); - MotorA.torque(forceA); + MotorA.torque(forceA); // forceA [-512 to +511] ??? MotorB.torque(forceB); - - Midi.checkMidi(); - } diff --git a/software/lib/MMM/Midi.cpp b/software/lib/MMM/Midi.cpp index fbbf440..6a72100 100644 --- a/software/lib/MMM/Midi.cpp +++ b/software/lib/MMM/Midi.cpp @@ -195,16 +195,13 @@ void MMidi::controller(uint8_t channel, uint8_t number, uint8_t value) { } break; case GAIN1: - //Music.setGain1(uint16_t(value * 512)); - Music.setGain1(value / 127.0); + Music.setGain1(uint16_t(value * 512)); break; case GAIN2: - //Music.setGain2(uint16_t(value * 512)); - Music.setGain2(value / 127.0); + Music.setGain2(uint16_t(value * 512)); break; case GAIN3: - //Music.setGain3(uint16_t(value * 512)); - Music.setGain3(value / 127.0); + Music.setGain3(uint16_t(value * 512)); break; case WAVEFORM: Music.setWaveform(value / 8); diff --git a/software/lib/MMM/Music.cpp b/software/lib/MMM/Music.cpp index 7cab002..f4402bb 100644 --- a/software/lib/MMM/Music.cpp +++ b/software/lib/MMM/Music.cpp @@ -21,4 +21,756 @@ + contact: j.bak@ciid.dk */ -//#include "Music.h" +#include "Music.h" +#include "Wavetable.h" + +// Table of MIDI note values to frequency in Hertz +prog_uint16_t hertsTable[] PROGMEM = {8,8,9,9,10,10,11,12,12,13,14,15,16,17,18,19,20,21,23,24,25,27,29,30,32,34,36,38,41,43,46,48,51,54,58,61,65,69,73,77,82,87,92,97,103,109,116,123,130,138,146,155,164,174,184,195,207,219,233,246,261,277,293,311,329,349,369,391,415,440,466,493,523,554,587,622,659,698,739,783,830,880,932,987,1046,1108,1174,1244,1318,1396,1479,1567,1661,1760,1864,1975,2093,2217,2349,2489,2637,2793,2959,3135,3322,3520,3729,3951,4186,4434,4698,4978,5274,5587,5919,6271,6644,7040,7458,7902,8372,8869,9397,9956,10548,11175,11839,12543}; + +prog_uint32_t envTimeTable[] PROGMEM = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,33,34,35,36,37,38,39,41,42,43,45,46,48,49,51,53,55,57,59,61,63,65,67,70,73,75,78,81,85,88,92,96,100,104,109,114,119,125,131,138,146,154,163,172,183,195,209,225,242,261,284,310,341,379,425,482,556,654,792,998,1342,2030,4095}; + +float semitoneTable[] = {0.25,0.2648658,0.2806155,0.29730177,0.31498027,0.33370996,0.35355338,0.37457678,0.39685026,0.4204482,0.44544938,0.47193715,0.5,0.5297315,0.561231,0.59460354,0.62996054,0.6674199,0.70710677,0.74915355,0.7937005,0.8408964,0.8908987,0.9438743,1.0,1.0594631,1.122462,1.1892071,1.2599211,1.3348398,1.4142135,1.4983071,1.587401,1.6817929,1.7817974,1.8877486,2.0,2.1189263,2.244924,2.3784142,2.5198421,2.6696796,2.828427,2.9966142,3.174802,3.3635857,3.563595,3.7754972,4.0}; + +MMusic Music; + +// Defining which pins the SPI interface is connected to. +#define SPI_SCK 5 +#define SPI_MOSI 3 + + +////////////////////////////////////////////////////////// +// +// AUDIO INTERRUPT. USE EITHER 8bit or 12bitSine VERSION +// COMMENT OUT THE ONE YOU ARE NOT USING +// +////////////////////////////////////////////////////////// +ISR(TIMER2_COMPA_vect) { // timer 2 is audio interrupt timer + + OCR2A = 127; // don't change this + + Music.synthInterrupt8bit(); + +// Music.synthInterrupt12bitSine(); + +} + + + + +///////////////////////////////////// +// +// INITIALIZING FUNCTION +// +///////////////////////////////////// + +void MMusic::init() +{ + // clear interrupts. to make sure the interrupt timer doesn't start until we've set it up. + //cli(); + + // set up syntheziser + // this is the timer 2 audio rate timer, fires an interrupt at 15625 Hz sampling rate + TIMSK2 = 1<127) att = 127; + memcpy_P(&attack, &envTimeTable[127 - att],2); + //attack = envTimeTable[127 - att]; +} + + +void MMusic::setDecay(uint8_t dec) +{ + if(dec>127) dec = 127; + memcpy_P(&decay, &envTimeTable[127 - dec],2); + //decay = envTimeTable[127 - dec]; +} + + +void MMusic::setSustain(uint8_t sus) +{ + sustain = ((sus * MAX_ENV_GAIN)/128); +} + + +void MMusic::setRelease(uint8_t rel) +{ + if(rel>127) rel = 127; + memcpy_P(&release, &envTimeTable[127 - rel],2); + //release = envTimeTable[127 - rel]; +} + + +void MMusic::setVelSustain(uint8_t vel) +{ + velSustain = vel * (sustain / 128); +} + + +void MMusic::setVelPeak(uint8_t vel) +{ + velPeak = vel * (MAX_ENV_GAIN / 128); +} + + + + +///////////////////////////////////////////////////////// +// +// 8 BIT WAVETABLE - AUDIO INTERRUPT SERVICE ROUTINE +// +///////////////////////////////////////////////////////// + + +void inline MMusic::synthInterrupt8bit() +{ + PORTD &= ~(1<<3); + + // Frame sync low for SPI (making it low here so that we can measure lenght of interrupt with scope) + PORTD &= ~(1<<6); + + accumulator1 = accumulator1 + period1; + index1 = accumulator1 >> 8; + //oscil1 = 0; + memcpy_P(&oscil1, &waveTable[index1 + waveForm1],1); + sample = (oscil1 * gain1); + +#if(NUM_OSCILLATORS==2 || NUM_OSCILLATORS==3) + + accumulator2 = accumulator2 + period2; + index2 = accumulator2 >> 8; + //oscil2 = 0; + memcpy_P(&oscil2, &waveTable[index2 + waveForm2],1); + sample += (oscil2 * gain2); + +#endif +#if NUM_OSCILLATORS==3 + + accumulator3 = accumulator3 + period3; + index3 = accumulator3 >> 8; + //oscil3 = 0; + memcpy_P(&oscil3, &waveTable[index3 + waveForm3],1); + sample += (oscil3 * gain3); + +#endif + + sample >>= 10; + + + // 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<> 4; + memcpy_P(&oscil1, &sineTable[index1],2); + sample = (oscil1 * gain1) << 2; + +#if(NUM_OSCILLATORS==2 || NUM_OSCILLATORS==3) + + accumulator2 = accumulator2 + period2; + index2 = accumulator2 >> 4; + memcpy_P(&oscil2, &sineTable[index2],2); + sample += (oscil2 * gain2) << 2; + +#endif +#if NUM_OSCILLATORS==3 + + accumulator3 = accumulator3 + period3; + index3 = accumulator3 >> 4; + memcpy_P(&oscil3, &sineTable[index3],2); + sample += (oscil3 * gain3) << 2; + +#endif + + sample >>= 16; + + + // 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< -#include -#include - -#include "Wavetable.h" - - //////////////////////////////////// // // SET NUMBER OF OSCILLATORS HERE. // SHOULD BE 1, 2 or 3 // //////////////////////////////////// -//#define NUM_OSCILLATORS 3 //edited BV 29Jan13. +#define NUM_OSCILLATORS 3 //edited BV 29Jan13. // current sample rate is 15625 as defined in the init() section #define SAMPLE_RATE 15625 #ifndef NUM_OSCILLATORS - #define NUM_OSCILLATORS 1 + #error NUM_OSCILLATORS should be defined in the Music.h file in the libraries/MMM folder. #elif (NUM_OSCILLATORS == 1)||(NUM_OSCILLATORS == 2)||(NUM_OSCILLATORS == 3) #else -#error NUM_OSCILLATORS shall be 1, 2 or 3 + #error NUM_OSCILLATORS shall be 1, 2 or 3 #endif // Maximum possible value for amplification envelope #define MAX_ENV_GAIN 65535 - - -// Table of MIDI note values to frequency in Hertz -prog_uint16_t hertsTable[] PROGMEM = {8,8,9,9,10,10,11,12,12,13,14,15,16,17,18,19,20,21,23,24,25,27,29,30,32,34,36,38,41,43,46,48,51,54,58,61,65,69,73,77,82,87,92,97,103,109,116,123,130,138,146,155,164,174,184,195,207,219,233,246,261,277,293,311,329,349,369,391,415,440,466,493,523,554,587,622,659,698,739,783,830,880,932,987,1046,1108,1174,1244,1318,1396,1479,1567,1661,1760,1864,1975,2093,2217,2349,2489,2637,2793,2959,3135,3322,3520,3729,3951,4186,4434,4698,4978,5274,5587,5919,6271,6644,7040,7458,7902,8372,8869,9397,9956,10548,11175,11839,12543}; - -prog_uint32_t envTimeTable[] PROGMEM = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,33,34,35,36,37,38,39,41,42,43,45,46,48,49,51,53,55,57,59,61,63,65,67,70,73,75,78,81,85,88,92,96,100,104,109,114,119,125,131,138,146,154,163,172,183,195,209,225,242,261,284,310,341,379,425,482,556,654,792,998,1342,2030,4095}; - -float semitoneTable[] = {0.25,0.2648658,0.2806155,0.29730177,0.31498027,0.33370996,0.35355338,0.37457678,0.39685026,0.4204482,0.44544938,0.47193715,0.5,0.5297315,0.561231,0.59460354,0.62996054,0.6674199,0.70710677,0.74915355,0.7937005,0.8408964,0.8908987,0.9438743,1.0,1.0594631,1.122462,1.1892071,1.2599211,1.3348398,1.4142135,1.4983071,1.587401,1.6817929,1.7817974,1.8877486,2.0,2.1189263,2.244924,2.3784142,2.5198421,2.6696796,2.828427,2.9966142,3.174802,3.3635857,3.563595,3.7754972,4.0}; - -// Defining which pins the SPI interface is connected to. -#define SPI_SCK 5 -#define SPI_MOSI 3 - - - +#include "Arduino.h" +#include +#include +#include class MMusic { public: @@ -102,28 +83,24 @@ public: void setWaveform3(uint16_t waveForm); // // GAIN FUNCTIONS - //void setGainFloat(float value); // 0.0 - 1.0 - //void setGain16bit(uint16_t value); // 0 - 65535 - //void setGain(uint16_t value); // 0 - 65535 + void setGainFloat(float value); // 0.0 - 1.0 + void setGain16bit(uint16_t value); // 0 - 65535 + void setGain(uint16_t value); // 0 - 65535 void setGain(float value); // 0.0 - 1.0 USE THIS - //void setGain1(uint16_t value); // 0 - 65535 - //void setGain2(uint16_t value); // 0 - 65535 - //void setGain3(uint16_t value); // 0 - 65535 - //float getGainFloat(); // 0.0 - 1.0 USE THIS + void setGain1(uint16_t value); // 0 - 65535 + void setGain2(uint16_t value); // 0 - 65535 + void setGain3(uint16_t value); // 0 - 65535 void setGain1(float value); // 0.0 - 1.0 USE THIS void setGain2(float value); // 0.0 - 1.0 USE THIS void setGain3(float value); // 0.0 - 1.0 USE THIS - //float getGain1Float(); // 0.0 - 1.0 USE THIS - //float getGain2Float(); // 0.0 - 1.0 USE THIS - //float getGain3Float(); // 0.0 - 1.0 USE THIS - float getGain(); // 0.0 - 1.0 USE THIS - float getGain1(); // 0.0 - 1.0 USE THIS - float getGain2(); // 0.0 - 1.0 USE THIS - float getGain3(); // 0.0 - 1.0 USE THIS - //uint16_t getGain(); - //uint16_t getGain1(); - //uint16_t getGain2(); - //uint16_t getGain3(); + float getGain1Float(); // 0.0 - 1.0 USE THIS + float getGain2Float(); // 0.0 - 1.0 USE THIS + float getGain3Float(); // 0.0 - 1.0 USE THIS + float getGainFloat(); // 0.0 - 1.0 USE THIS + uint16_t getGain(); + uint16_t getGain1(); + uint16_t getGain2(); + uint16_t getGain3(); // NOTE FUNCTIONS void noteOn(uint8_t note, uint8_t vel); // 0 - 255 @@ -221,771 +198,4 @@ private: extern MMusic Music; - - -///////////////////////////////////////////////////////// -// -// 8 BIT WAVETABLE - AUDIO INTERRUPT SERVICE ROUTINE -// -///////////////////////////////////////////////////////// - - -void inline MMusic::synthInterrupt8bit() -{ - PORTD &= ~(1<<3); - - // Frame sync low for SPI (making it low here so that we can measure lenght of interrupt with scope) - PORTD &= ~(1<<6); - - accumulator1 = accumulator1 + period1; - index1 = accumulator1 >> 8; - //oscil1 = 0; - memcpy_P(&oscil1, &waveTable[index1 + waveForm1],1); - sample = (oscil1 * gain1); - -#if (NUM_OSCILLATORS==2) || (NUM_OSCILLATORS==3) - - accumulator2 = accumulator2 + period2; - index2 = accumulator2 >> 8; - //oscil2 = 0; - memcpy_P(&oscil2, &waveTable[index2 + waveForm2],1); - sample += (oscil2 * gain2); - -#endif -#if NUM_OSCILLATORS==3 - - accumulator3 = accumulator3 + period3; - index3 = accumulator3 >> 8; - //oscil3 = 0; - memcpy_P(&oscil3, &waveTable[index3 + waveForm3],1); - sample += (oscil3 * gain3); - -#endif - - sample >>= 10; - - - // 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<> 4; - memcpy_P(&oscil1, &sineTable[index1],2); - sample = (oscil1 * gain1) << 2; - -#if (NUM_OSCILLATORS==2) || (NUM_OSCILLATORS==3) - - accumulator2 = accumulator2 + period2; - index2 = accumulator2 >> 4; - memcpy_P(&oscil2, &sineTable[index2],2); - sample += (oscil2 * gain2) << 2; - -#endif -#if NUM_OSCILLATORS==3 - - accumulator3 = accumulator3 + period3; - index3 = accumulator3 >> 4; - memcpy_P(&oscil3, &sineTable[index3],2); - sample += (oscil3 * gain3) << 2; - -#endif - - sample >>= 16; - - - // 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<127) att = 127; - memcpy_P(&attack, &envTimeTable[127 - att],2); - //attack = envTimeTable[127 - att]; -} - - -void MMusic::setDecay(uint8_t dec) -{ - if(dec>127) dec = 127; - memcpy_P(&decay, &envTimeTable[127 - dec],2); - //decay = envTimeTable[127 - dec]; -} - - -void MMusic::setSustain(uint8_t sus) -{ - sustain = ((sus * MAX_ENV_GAIN)/128); -} - - -void MMusic::setRelease(uint8_t rel) -{ - if(rel>127) rel = 127; - memcpy_P(&release, &envTimeTable[127 - rel],2); - //release = envTimeTable[127 - rel]; -} - - -void MMusic::setVelSustain(uint8_t vel) -{ - velSustain = vel * (sustain / 128); -} - - -void MMusic::setVelPeak(uint8_t vel) -{ - velPeak = vel * (MAX_ENV_GAIN / 128); -} - - - - - - - - #endif // close guard