![]() |
Mozzi
alpha 0.01.1m
sound synthesis library for Arduino
|
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