Mozzi  alpha 0.01.1m
sound synthesis library for Arduino
 All Classes Functions
examples/_02b_FMsynth/build-uno/_02b_FMsynth.cpp
00001 #include <Arduino.h>
00002 /*  Example of simple FM with the phase modulation technique,
00003  *  using Mozzi sonification library.
00004  *
00005  *  Demonstrates Oscil::phMod() for phase modulation, 
00006  *  Smooth() for smoothing control signals, 
00007  *  and Mozzi's fixed point number types for fractional frequencies.
00008  *
00009  *  Also shows the limitations of Mozzi's 16384Hz Sample rate,
00010  *  as aliasing audibly intrudes as the sound gets brighter around 
00011  *  midi note 48.
00012  *  
00013  *  Circuit: Audio output on digital pin 9.
00014  *
00015  *  Mozzi help/discussion/announcements:
00016  *  https://groups.google.com/forum/#!forum/mozzi-users
00017  *
00018  *  Tim Barrass 2012.
00019  *  This example code is in the public domain.
00020  */
00021 
00022 #include <MozziGuts.h>
00023 #include <Oscil.h>
00024 #include <tables/cos2048_int8.h> // table for Oscils to play
00025 #include <utils.h>
00026 #include <fixedMath.h>
00027 #include <EventDelay.h>
00028 #include <Smooth.h>
00029 
00030 #define CONTROL_RATE 256 // powers of 2 please
00031 
00032 Oscil<COS2048_NUM_CELLS, AUDIO_RATE> aCarrier(COS2048_DATA);
00033 Oscil<COS2048_NUM_CELLS, AUDIO_RATE> aModulator(COS2048_DATA);
00034 Oscil<COS2048_NUM_CELLS, CONTROL_RATE> kModIndex(COS2048_DATA);
00035 
00036 // The ratio of deviation to modulation frequency is called the "index of modulation". ( I = d / Fm )
00037 // It will vary according to the frequency that is modulating the carrier and the amount of deviation.
00038 // so deviation d = I * Fm
00039 // haven't quite worked this out properly yet...
00040 
00041 Q8n8 mod_index;// = float_to_Q8n8(2.0f); // constant version
00042 Q16n16 deviation;
00043 
00044 Q16n16 carrier_freq, mod_freq;
00045 
00046 // FM ratio between oscillator frequencies, stays the same through note range
00047 Q8n8 mod_to_carrier_ratio = float_to_Q8n8(3.f);
00048 
00049 EventDelay kNoteChangeDelay(CONTROL_RATE);
00050 
00051 // for note changes
00052 Q7n8 target_note, note0, note1, note_upper_limit, note_lower_limit, note_change_step, smoothed_note;
00053 
00054 // using Smooth on midi notes rather than frequency, 
00055 // because fractional frequencies need larger types than Smooth can handle
00056 // Inefficient, but...until there is a better Smooth....
00057 Smooth <int> kSmoothNote(0.95f);
00058 
00059 void setup(){
00060   kNoteChangeDelay.set(768); // ms countdown, taylored to resolution of CONTROL_RATE
00061   kModIndex.setFreq(.768f); // sync with kNoteChangeDelay
00062   target_note = note0;
00063   note_change_step = Q7n0_to_Q7n8(3);
00064   note_upper_limit = Q7n0_to_Q7n8(50);
00065   note_lower_limit = Q7n0_to_Q7n8(32);
00066   note0 = note_lower_limit;
00067   note1 = note_lower_limit + Q7n0_to_Q7n8(5);
00068   startMozzi(CONTROL_RATE);
00069 }
00070 
00071 void setFreqs(Q8n8 midi_note){
00072   carrier_freq = Q16n16_mtof(Q8n8_to_Q16n16(midi_note)); // convert midi note to fractional frequency
00073   mod_freq = ((carrier_freq>>8) * mod_to_carrier_ratio)  ; // (Q16n16>>8) * Q8n8 = Q16n16, beware of overflow
00074   deviation = ((mod_freq>>16) * mod_index); // (Q16n16>>16) * Q8n8 = Q24n8, beware of overflow
00075   aCarrier.setFreq_Q16n16(carrier_freq);
00076   aModulator.setFreq_Q16n16(mod_freq);
00077 }
00078 
00079 void updateControl(){
00080   // change note
00081   if(kNoteChangeDelay.ready()){
00082     if (target_note==note0){
00083       note1 += note_change_step;
00084       target_note=note1;
00085     }
00086     else{ 
00087       note0 += note_change_step;
00088       target_note=note0;
00089     }
00090 
00091     // change direction
00092     if(note0>note_upper_limit) note_change_step = Q7n0_to_Q7n8(-3);
00093     if(note0<note_lower_limit) note_change_step = Q7n0_to_Q7n8(3);
00094     
00095     // reset eventdelay
00096     kNoteChangeDelay.start();
00097   }
00098   
00099   // vary the modulation index
00100   mod_index = (Q8n8)350+kModIndex.next();
00101   
00102   // here's where the smoothing happens
00103   smoothed_note = kSmoothNote.next(target_note);
00104   setFreqs(smoothed_note);
00105 
00106 }
00107 
00108 
00109 int updateAudio(){
00110   Q15n16 modulation = deviation * aModulator.next() >> 8;
00111   return (int)aCarrier.phMod(modulation);
00112 }
00113 
00114 
00115 void loop(){
00116   audioHook();
00117 }
00118 
00119 
00120 
00121