/* Example of a sound being triggered by MIDI input. * * Demonstrates playing notes with Mozzi in response to MIDI input, * using the standard Arduino MIDI library: * http://playground.arduino.cc/Main/MIDILibrary * * Mozzi help/discussion/announcements: * https://groups.google.com/forum/#!forum/mozzi-users * * Tim Barrass 2013. * This example code is in the public domain. * * sgreen - modified to use standard Arduino midi library, added saw wave, lowpass filter * Audio output from pin 9 (pwm) * Midi plug pin 2 (centre) to Arduino gnd, pin 5 to RX (0) * http://www.philrees.co.uk/midiplug.htm * * dgreen - nutty portamento added! */ #include #include #include // oscillator template #include // for envelope #include #include #include #include #include // table for Oscils to play #include // table for Oscils to play // use #define for CONTROL_RATE, not a constant #define CONTROL_RATE 256 // powers of 2 please // Mozzi example uses COS waves for carrier and modulator // Shit gets brutal very fast if you use a saw/square carrier // Shit gets subtly more brutal if you use smaller wavetables (fewer samples per cycle) Oscil oscCarrierMaster(SAW_ANALOGUE512_DATA); Oscil oscCarrierSlave1(SAW_ANALOGUE512_DATA); Oscil oscCarrierSlave2(SAW_ANALOGUE512_DATA); Oscil oscModulator(COS2048_DATA); Oscil oscLFO(COS2048_DATA); // envelope generator ADSR envelope; Portamento aPortamento; MIDI_CREATE_DEFAULT_INSTANCE(); #define LED 13 // to see if MIDI is being recieved unsigned long vibrato = 0; float carrierFreq = 10.f; float modFreq = 10.f; float modDepth = 0.5; float amplitude = 0.f; float modOffset = 1; byte lastnote = 0; int portSpeed = 100; float detuneCoefficient1 = 1; float detuneCoefficient2 = 1; float modOffsets[] = { 4, 3.5, 3, 2.5, 2, 1.5, 1, 0.6666667, 0.5, 0.4, 0.3333333, 0.2857, 0.25, 0, 0, 0, 0, 0, 0 }; // freq ratios corresponding to DP's preferred intervals of 7, 12, 7, 19, 24, 0, 12, -12, etc void setup() { pinMode(LED, OUTPUT); MIDI.begin(MIDI_CHANNEL_OMNI); MIDI.setHandleNoteOn(HandleNoteOn); MIDI.setHandleNoteOff(HandleNoteOff); MIDI.setHandleControlChange(HandleControlChange); MIDI.setHandlePitchBend(HandlePitchBend); MIDI.setHandleProgramChange(HandleProgramChange); MIDI.setHandleContinue(HandleContinue); envelope.setADLevels(255, 174); envelope.setTimes(10, 50, 50, 1000); // 20000 is so the note will sustain 20 seconds unless a noteOff comes aPortamento.setTime(50u); oscLFO.setFreq(10); // default frequency startMozzi(CONTROL_RATE); } void HandleProgramChange (byte channel, byte number) { // Use MIDI Program Change to select an interval between carrier and modulator oscillator modOffset = modOffsets[number % 15]; } void HandleNoteOn(byte channel, byte note, byte velocity) { aPortamento.start((byte)(((int) note) - 5)); lastnote = note; envelope.noteOn(); digitalWrite(LED, HIGH); } void HandleContinue () { portSpeed += 100; if (portSpeed > 500) { portSpeed = 0; } aPortamento.setTime(portSpeed); } void HandleNoteOff(byte channel, byte note, byte velocity) { if (note == lastnote) { envelope.noteOff(); digitalWrite(LED, LOW); } } void HandlePitchBend (byte channel, int bend) { float shifted = float ((bend + 8500) / 2048.f) + 0.1f; oscLFO.setFreq(shifted); } void HandleControlChange (byte channel, byte number, byte value) { if(number == 1) { float divided = float(value / 46.f); modDepth = (divided * divided); if (modDepth > 5) { modDepth = 5; } if (modDepth < 0.2) { modDepth = 0; } } } void updateControl() { MIDI.read(); envelope.update(); carrierFreq = Q16n16_to_float (aPortamento.next()); //NB presumably returns frequency as Q16n16 modFreq = carrierFreq * modOffset; const unsigned short cents = 40; detuneCoefficient1 = 1 + 0.0005946 * cents; detuneCoefficient2 = 1 - 0.0005946 * cents; // set carrier frequencies oscCarrierMaster.setFreq(carrierFreq); oscCarrierSlave1.setFreq(carrierFreq * detuneCoefficient1); oscCarrierSlave2.setFreq(carrierFreq * detuneCoefficient2); oscModulator.setFreq(modFreq); } int updateAudio() { vibrato = (unsigned long) (oscLFO.next() * oscModulator.next()) >> 7; vibrato *= (unsigned long) (carrierFreq * modDepth) >> 3; int carrierSum = (oscCarrierMaster.phMod(vibrato) + oscCarrierSlave1.phMod(vibrato) + oscCarrierSlave2.phMod(vibrato)) >> 3; return (int) (carrierSum * (envelope.next())) >> 8; } void loop() { audioHook(); }