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