Skip to content

Commit e6b800a

Browse files
authored
Merge pull request #107 from pingdynasty/feature/hwplatforms
feature/hwplatforms
2 parents 267b96e + 38917c0 commit e6b800a

14 files changed

Lines changed: 626 additions & 40 deletions

HISTORY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
v22.2
22
-----
3+
4+
* Added PLATFORM=OWL1/2/3 build option
35
* Added NoiseOscillator (whitenoise s+h)
46
* Added PhaseShiftOscillator template
57
* Added Biquad allpass filter configuration

LibSource/BiquadFilter.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,15 @@ class BiquadFilter : public SignalProcessor {
220220
init();
221221
}
222222
virtual ~BiquadFilter(){}
223+
223224
void setSampleRate(float sr){
224225
pioversr = M_PI/sr;
225226
}
226227

228+
float getSampleRate(){
229+
return M_PI / pioversr;
230+
}
231+
227232
size_t getStages(){
228233
return stages;
229234
}
@@ -274,13 +279,14 @@ class BiquadFilter : public SignalProcessor {
274279
arm_biquad_cascade_df2T_f32(&df2, input, output, size);
275280
#else
276281
for(size_t k=0; k<stages; k++){
277-
float b0=getFilterStage(k).getCoefficients()[0];
278-
float b1=getFilterStage(k).getCoefficients()[1];
279-
float b2=getFilterStage(k).getCoefficients()[2];
280-
float a1=getFilterStage(k).getCoefficients()[3];
281-
float a2=getFilterStage(k).getCoefficients()[4];
282-
float d1=state[k*BIQUAD_STATE_VARIABLES_PER_STAGE];
283-
float d2=state[k*BIQUAD_STATE_VARIABLES_PER_STAGE+1];
282+
float* coeffs = getFilterStage(k).getCoefficients();
283+
float b0 = *coeffs++;
284+
float b1 = *coeffs++;
285+
float b2 = *coeffs++;
286+
float a1 = *coeffs++;
287+
float a2 = *coeffs++;
288+
float d1 = state[k*BIQUAD_STATE_VARIABLES_PER_STAGE];
289+
float d2 = state[k*BIQUAD_STATE_VARIABLES_PER_STAGE+1];
284290
for(size_t n=0; n<size; n++){ //manually apply filter, one stage
285291
float out=b0 * input[n] + d1;
286292
d1 = b1 * input[n] + a1 * out + d2;

LibSource/DcBlockingFilter.h

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,35 @@
55
#include "SignalProcessor.h"
66

77
/**
8-
* DC Blocking IIR filter:
9-
* Leaky differentiator.
8+
* DC Blocking IIR filter, aka Leaky differentiator.
9+
* Ref: https://www.dsprelated.com/freebooks/filters/DC_Blocker.html
1010
*/
1111
class DcBlockingFilter : public SignalProcessor {
1212
private:
13-
const float lambda;
1413
float x1, y1;
14+
float R;
1515
public:
16-
DcBlockingFilter(float lambda = 0.995): lambda(lambda), x1(0), y1(0) {}
16+
DcBlockingFilter(float R = 0.995): R(R), x1(0), y1(0) {}
1717

18+
/**
19+
* Get adaptation time constant in samples.
20+
*/
21+
float getTimeConstant(){
22+
return 1/(1-R); // approximate
23+
}
24+
/**
25+
* Set adaptation time constant in samples.
26+
*/
27+
void setTimeConstant(float tc){
28+
R = (tc - 1) / tc;
29+
}
1830
void reset(){
1931
x1 = y1 = 0;
2032
}
2133

2234
/* process a single sample and return the result */
2335
float process(float x){
24-
y1 = x - x1 + lambda*y1;
36+
y1 = x - x1 + R*y1;
2537
x1 = x;
2638
return y1;
2739
}
@@ -31,7 +43,7 @@ class DcBlockingFilter : public SignalProcessor {
3143
float y = y1;
3244
while(size--){
3345
x = *input++;
34-
y = x - x1 + lambda*y;
46+
y = x - x1 + R*y;
3547
x1 = x;
3648
*output++ = y;
3749
}
@@ -52,8 +64,8 @@ class DcBlockingFilter : public SignalProcessor {
5264
process(in, out, in.getSize());
5365
}
5466

55-
static DcBlockingFilter* create(float lambda=0.995){
56-
return new DcBlockingFilter(lambda);
67+
static DcBlockingFilter* create(float R=0.995){
68+
return new DcBlockingFilter(R);
5769
}
5870

5971
static void destroy(DcBlockingFilter* obj){
@@ -65,14 +77,29 @@ class StereoDcBlockingFilter : public MultiSignalProcessor {
6577
private:
6678
DcBlockingFilter left, right;
6779
public:
68-
StereoDcBlockingFilter(float lambda = 0.995): left(lambda), right(lambda) {}
80+
StereoDcBlockingFilter(float R = 0.995): left(R), right(R) {}
81+
82+
/**
83+
* Get adaptation time constant in samples.
84+
*/
85+
float getTimeConstant(){
86+
return left.getTimeConstant();
87+
}
88+
/**
89+
* Set adaptation time constant in samples.
90+
*/
91+
void setTimeConstant(float tc){
92+
left.setTimeConstant(tc);
93+
right.setTimeConstant(tc);
94+
}
95+
6996
void process(AudioBuffer& input, AudioBuffer& output){
7097
left.process(input.getSamples(LEFT_CHANNEL), output.getSamples(LEFT_CHANNEL));
7198
right.process(input.getSamples(RIGHT_CHANNEL), output.getSamples(RIGHT_CHANNEL));
7299
}
73100

74-
static StereoDcBlockingFilter* create(float lambda){
75-
return new StereoDcBlockingFilter(lambda);
101+
static StereoDcBlockingFilter* create(float R=0.995){
102+
return new StereoDcBlockingFilter(R);
76103
}
77104

78105
static void destroy(StereoDcBlockingFilter* obj){

LibSource/InterpolatingCircularBuffer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ class InterpolatingCircularFloatBuffer : public CircularBuffer<float> {
3232
* Interpolated read at fractional rate
3333
* @param rate read speed, in samples/sample
3434
*/
35-
void read(float* out, size_t len, float rate){
36-
float pos = readpos; // quantizes fractional read pos from last read
35+
void read(float* out, size_t len, float startpos, float rate){
36+
float pos = startpos;
3737
while(len--){
3838
*out++ = readAt(pos);
3939
pos += rate;

LibSource/SquareWaveOscillator.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,57 @@ class AntialiasedSquareWaveOscillator : public OscillatorTemplate<AntialiasedSqu
5959
sample -= polyblep(fmod(phase + 1 - pw, 1), incr);
6060
return sample;
6161
}
62+
void generate(FloatArray output){
63+
float sample;
64+
if(phase < pw){
65+
sample = 1;
66+
if(phase < incr){
67+
float t = phase / incr;
68+
sample += t+t - t*t - 1;
69+
}
70+
}else{
71+
sample = -1;
72+
if(phase-pw < incr){
73+
float t = fmod(phase + 1 - pw, 1) / incr;
74+
sample -= t+t - t*t - 1;
75+
}
76+
}
77+
size_t len = output.getSize();
78+
float* dest = output.getData();
79+
while(len--){
80+
phase += incr;
81+
if(phase >= pw){
82+
if(phase >= 1){
83+
// wrap phase
84+
phase -= 1;
85+
// correct current sample
86+
float t = (phase - incr) / incr;
87+
sample += t*t + t+t + 1;
88+
*dest++ = sample;
89+
sample = 1;
90+
// correct next sample
91+
t = phase / incr;
92+
sample += t+t - t*t - 1;
93+
}else if(sample == 1){
94+
// correct current sample
95+
float t = (fmod(phase + 1 - pw, 1) - incr) / incr;
96+
sample -= t*t + t+t + 1;
97+
*dest++ = sample;
98+
sample = -1;
99+
// correct next sample
100+
t = fmod(phase + 1 - pw, 1) / incr;
101+
sample -= t+t - t*t - 1;
102+
}else{
103+
*dest++ = sample;
104+
sample = -1;
105+
}
106+
}else{
107+
*dest++ = sample;
108+
sample = 1;
109+
}
110+
}
111+
}
112+
using OscillatorTemplate<AntialiasedSquareWaveOscillator>::generate;
62113
};
63114

64115
#endif /* __SquareWaveOscillator_h */

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ endif
99
endif
1010

1111
ifndef PLATFORM
12-
PLATFORM=OWL
12+
PLATFORM=OWL2
1313
endif
1414

1515
DEPS = .FORCE

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Make sure to do a `make clean` before compiling a new patch, or add `clean` to y
8787
* PATCHOUT: number of output channels, default 2
8888
* SLOT: user program slot to store patch in, default 0, use with `store`
8989
* TARGET: changes the output prefix, default 'patch'
90-
90+
* PLATFORM: changes the target platform: OWL1, OWL2 (default) or OWL3
9191

9292
All files for a patch must be copied to the `PATCHSOURCE` directory. Take care to put only files required by the patch you want to compile here.
9393

@@ -158,6 +158,19 @@ Specify your patch name (and optionally the PATCHSOURCE directory) as usual, but
158158
* `make SOUL=Foo clean patch`
159159

160160

161+
## Target Platform
162+
163+
Most patches will compile to run on all OWL devices by default. However there are some platform differences, notably the maximum binary size (in kilobytes):
164+
165+
* OWL1 (Legacy OWL Pedal and OWL Modular): 64K
166+
* OWL2 (OWL Pedal mkII, Alchemist, Wizard, Magus, Witch, Lich): 144K
167+
* OWL3 (Genius, Xibeca): 80K or 512K
168+
169+
The target platform can be selected with the `PLATFORM` option, which defaults to `OWL2`. This can create patches up to 144K in binary size. Patches over 64K will not run on OWL1 devices, and patches over 80K will not run on OWL3 devices.
170+
171+
To verify that a patch will run on all devices you can compile with `PLATFORM=OWL1`. Patches over 64K in binary size will then fail with a link error.
172+
173+
Alternatively, to target **exclusively** OWL3 devices you can specify `PLATFORM=OWL3`. This will primarily do two things: firstly link the binary against D1 memory allowing patches up to 512K, secondly enable double precision FPU. Both of these features are only available on the Cortex M7 microcontrollers used by OWL3 devices. Patches compiled with this option will not run on OWL1 or OWL2 devices.
161174

162175
# Examples
163176

Source/PatchProcessor.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,6 @@ void PatchProcessor::setPatch(Patch* p, const char* n){
3838
name = n;
3939
}
4040

41-
AudioBuffer* PatchProcessor::createMemoryBuffer(int channels, int size){
42-
MemoryBuffer* buf = new ManagedMemoryBuffer(channels, size);
43-
if(buf == NULL)
44-
return NULL;
45-
buffers[bufferCount++] = buf;
46-
buf->clear();
47-
return buf;
48-
}
49-
5041
void PatchProcessor::setParameterValues(int16_t *params){
5142
if(getProgramVector()->hardware_version == OWL_MODULAR_HARDWARE){
5243
for(int i=0; i<4 && i<parameterCount; ++i)

Source/PatchProcessor.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ class PatchProcessor {
2424
}
2525
int getBlockSize();
2626
double getSampleRate();
27-
AudioBuffer* createMemoryBuffer(int channels, int samples);
2827
void setParameterValues(int16_t* parameters);
2928
Patch* patch;
3029
uint8_t index;

0 commit comments

Comments
 (0)