Mozzi  version v2.0
sound synthesis library for Arduino
PDResonant.h
1 /*
2  * PDResonant.h
3  *
4  * This file is part of Mozzi.
5  *
6  * Copyright 2013-2024 Tim Barrass and the Mozzi Team
7  *
8  * Mozzi is licensed under the GNU Lesser General Public Licence (LGPL) Version 2.1 or later.
9  *
10  */
11 
12 #include <mozzi_midi.h>
13 #include <ADSR.h>
14 #include <Oscil.h>
15 #include <Phasor.h>
16 // wavetable for oscillator:
17 #include <tables/sin2048_int8.h>
18 
19 /**
20  PDResonant is a simple midi instrument using Phase distortion used to simulate resonant filter, based on
21  https://en.wikipedia.org/wiki/Phase_distortion_synthesis.
22 
23  The class shows how the Mozzi Phasor class
24  can be used to generate an index into a wavetable, and an ADSR
25  is used to modulate the effect by modifying the Phasor frequency and sync.
26  More complex phase distortion effects could be developed by using
27  precalculated tables, or calcuating tables on the fly using a double buffer,
28  or a line-breakpoint model, a sort of hybridPhasor-Line object.
29 */
30 
32 {
33 
34 public:
35 
36  /** Constructor.
37  */
39  PDM_SCALE(0.05)
40  {
41  aOsc.setTable(SIN2048_DATA);
42  aAmpEnv.setADLevels(255, 255);
43  aAmpEnv.setTimes(50, 300, 60000, 1000);
44  kResonantFreqEnv.setADLevels(255,100);
45  }
46 
47  /** Play a note in response to midi input. Params copied from MIDI library HandleNoteOn().
48  @param channel is the midi channel
49  @param pitch is the midi note
50  @param velocity you know what it is
51  */
52  void noteOn(byte channel, byte pitch, byte velocity)
53  {
54  kResonantFreqEnv.noteOn();
55  aAmpEnv.noteOn();
56  freq = mtof(pitch);
57  aBaseCounter.setFreq(freq); // gets modulated in updateControl()
58  aResonanceFreqCounter.setFreq(freq);
59  }
60 
61 
62  /** Stop a note in response to midi input. Params copied from MIDI library HandleNoteOff()
63  @param channel is the midi channel
64  @param pitch is the midi note
65  @param velocity you know what it is
66  */
67  void noteOff(byte channel, byte pitch, byte velocity)
68  {
69  aAmpEnv.noteOff();
70  kResonantFreqEnv.noteOff();
71  }
72 
73 
74  /** Set the resonant filter sweep parameters.
75  @param attack ADSR attack
76  @param decay ADSR decay
77  */
78  void setPDEnv(int attack, int decay)
79  {
80  // sustain and release timesare hardcoded here but don't need to be
81  kResonantFreqEnv.setTimes(attack, decay, 60000, 1000);
82  kResonantFreqEnv.update();
83 
84  float resonance_freq = freq + ((float)freq * ((float)kResonantFreqEnv.next()*PDM_SCALE));
85  aResonanceFreqCounter.setFreq(resonance_freq);
86  }
87 
88 
89  /** Update the filter sweep. Use this in updateControl().
90  */
91  void update()
92  {
93  aAmpEnv.update();
94  kResonantFreqEnv.update();
95  // change freq of resonant freq counter, following the envelope
96  float resonance_freq = freq + ((float)freq * ((float)kResonantFreqEnv.next()*PDM_SCALE));
97  aResonanceFreqCounter.setFreq(resonance_freq);
98  }
99 
100  /** Produce the audio output. This goes in updateAudio().
101  */
102  int next()
103  {
104  static byte previous_base_counter;
105  byte base_counter = aBaseCounter.next()>>24;
106 
107  // reset resonance counter (wiki b.)
108  if (base_counter<previous_base_counter) aResonanceFreqCounter.set(0);
109  previous_base_counter= base_counter;
110 
111  // index (phase) needs to end up as 11bit to match 2048 wavetable size
112  unsigned int index = aResonanceFreqCounter.next()>>21; // 11 bits fits 2048 cell sin table
113 
114  // amp ramp smooths the jump when aResonanceFreqCounter is reset (wiki d.)
115  byte amp_ramp = 255-base_counter;
116 
117  // wiki e., with amp envelope added
118  return ((long)aAmpEnv.next() * amp_ramp * aOsc.atIndex(index))>>16;
119 
120  // return ((index>>3)*amp_ramp)>>8; // this also sounds good - squelchy sawtooth
121  }
122 
123 
124 private:
125  const float PDM_SCALE;
126  byte amp;
127  int freq;
128 
129  Phasor <MOZZI_AUDIO_RATE> aBaseCounter;
130  Phasor <MOZZI_AUDIO_RATE> aResonanceFreqCounter;
131 
132  Oscil <SIN2048_NUM_CELLS, MOZZI_AUDIO_RATE> aOsc;
133  ADSR <MOZZI_CONTROL_RATE, MOZZI_AUDIO_RATE> aAmpEnv;
134  ADSR <MOZZI_CONTROL_RATE, MOZZI_CONTROL_RATE> kResonantFreqEnv;
135 
136 };