Skip to content

Commit

Permalink
added Wavetable + example, cleaned up
Browse files Browse the repository at this point in the history
  • Loading branch information
dennisppaul committed Nov 9, 2020
1 parent 74114e4 commit 80cd092
Show file tree
Hide file tree
Showing 20 changed files with 949 additions and 340 deletions.
Binary file modified lib/ton.jar
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -51,29 +51,27 @@ void audioblock(float[] pOutputSamples) {
mSample = mButterworthLowPassFilter.filter(mSample);
}
mSample = DSP.clamp(mSample, -1, 1);
pOutputSamples[i] = mLPFilter.filter(mSample);
pOutputSamples[i] = mSample;
}
}
interface filter_constants {
float sqrt2 = (float) (2.0 * 3.1415926535897932384626433832795);
float pi = (float) (2.0 * 0.707106781186547524401);
}
/**
* Second order Butterworth low-pass filter
* Dimitris Tassopoulos 2016
* Second order Butterworth low-pass filter Dimitris Tassopoulos 2016
* <p>
* fc, corner frequency
* Butterworth low-pass and high-pass filters are specialized versions of the ordinary secondorder
* low-pass filter. Their Q values are fixed at 0.707, which is the largest value it can
* assume before peaking in the frequency response is observed.
* fc, corner frequency Butterworth low-pass and high-pass filters are specialized versions of the ordinary
* secondorder low-pass filter. Their Q values are fixed at 0.707, which is the largest value it can assume before
* peaking in the frequency response is observed.
* <p>
* from https://github.com/dimtass/DSP-Cpp-filters
*/
static class ButterworthLowPassFilter {
float m_xnz1, m_xnz2, m_ynz1, m_ynz2;
tp_coeffs m_coeffs = new tp_coeffs();
tp_coeffs calculate_coeffs(int fc) {
final int fs = 44100;
final int fs = DSP.DEFAULT_SAMPLING_RATE;
float c = 1.0f / (tan(filter_constants.pi * fc / fs));
m_coeffs.a0 = 1.0f / (1.0f + filter_constants.sqrt2 * c + pow(c, 2.0f));
m_coeffs.a1 = 2.0f * m_coeffs.a0;
Expand All @@ -84,7 +82,8 @@ static class ButterworthLowPassFilter {
}
float filter(float sample) {
float xn = sample;
float yn = m_coeffs.a0 * xn + m_coeffs.a1 * m_xnz1 + m_coeffs.a2 * m_xnz2 - m_coeffs.b1 * m_ynz1 - m_coeffs.b2 * m_xnz2;
float yn =
m_coeffs.a0 * xn + m_coeffs.a1 * m_xnz1 + m_coeffs.a2 * m_xnz2 - m_coeffs.b1 * m_ynz1 - m_coeffs.b2 * m_xnz2;
m_xnz2 = m_xnz1;
m_xnz1 = xn;
m_xnz2 = m_ynz1;
Expand All @@ -93,19 +92,17 @@ static class ButterworthLowPassFilter {
}
}
/**
* Second order Low-pass filter
* Dimitris Tassopoulos 2016
* Second order Low-pass filter Dimitris Tassopoulos 2016
* <p>
* fc , corner frequency
* Q , quality factor controlling resonant peaking
* fc , corner frequency Q , quality factor controlling resonant peaking
* <p>
* from https://github.com/dimtass/DSP-Cpp-filters
*/
static class SecondOrderLowPassFilter {
float m_xnz1, m_xnz2, m_ynz1, m_ynz2;
tp_coeffs m_coeffs = new tp_coeffs();
tp_coeffs calculate_coeffs(float Q, int fc) {
final int fs = 44100;
final int fs = DSP.DEFAULT_SAMPLING_RATE;
float w = 2.0f * filter_constants.pi * fc / fs;
float d = 1.0f / Q;
float b = 0.5f * (1.0f - (d / 2) * sin(w)) / (1.0f + (d / 2.0f) * sin(w));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import de.hfkbremen.ton.*;
import controlP5.*;
import ddf.minim.*;
import com.jsyn.unitgen.*;


final Wavetable mWavetable = new Wavetable(1024);
void settings() {
size(640, 480);
}
void setup() {
DSP.dumpAudioDevices();
DSP.start(this);
triangle(mWavetable.wavetable());
}
void draw() {
background(255);
DSP.draw_buffer(g, width, height);
}
void mouseMoved() {
mWavetable.set_frequency(map(mouseX, 0, width, 55, 220));
mWavetable.set_amplitude(map(mouseY, 0, height, 0.0f, 0.9f));
}
void keyPressed() {
switch (key) {
case '1':
sine(mWavetable.wavetable());
break;
case '2':
sawtooth(mWavetable.wavetable());
break;
case '3':
triangle(mWavetable.wavetable());
break;
case '4':
square(mWavetable.wavetable());
break;
case '5':
randomize(mWavetable.wavetable());
break;
}
}
void audioblock(float[] pOutputSamples) {
for (int i = 0; i < pOutputSamples.length; i++) {
pOutputSamples[i] = mWavetable.process();
}
}
void randomize(float[] pWavetable) {
for (int i = 0; i < pWavetable.length; i++) {
pWavetable[i] = random(-1, 1);
}
}
static void sine(float[] pWavetable) {
for (int i = 0; i < pWavetable.length; i++) {
pWavetable[i] = PApplet.sin(2.0f * PI * ((float) i / (float) (pWavetable.length)));
}
}
static void sawtooth(float[] pWavetable) {
for (int i = 0; i < pWavetable.length; i++) {
pWavetable[i] = 2.0f * ((float) i / (float) (pWavetable.length - 1)) - 1.0f;
}
}
static void triangle(float[] pWavetable) {
final int q = pWavetable.length / 4;
final float qf = pWavetable.length * 0.25f;
for (int i = 0; i < q; i++) {
pWavetable[i] = i / qf;
pWavetable[i + (q * 1)] = (qf - i) / qf;
pWavetable[i + (q * 2)] = -i / qf;
pWavetable[i + (q * 3)] = -(qf - i) / qf;
}
}
static void square(float[] pWavetable) {
for (int i = 0; i < pWavetable.length / 2; i++) {
pWavetable[i] = 1.0f;
pWavetable[i + pWavetable.length / 2] = -1.0f;
}
}
static class Wavetable {
final float[] mWavetable;
float mFrequency;
float mStepSize;
float mArrayPtr;
float mAmplitude;
Wavetable(int pWavetableSize) {
mWavetable = new float[pWavetableSize];
mArrayPtr = 0;
mAmplitude = 0.75f;
set_frequency(220);
}
void set_frequency(float pFrequency) {
if (mFrequency != pFrequency) {
mFrequency = pFrequency;
mStepSize = mFrequency * ((float) mWavetable.length / (float) DSP.DEFAULT_SAMPLING_RATE);
}
}
void set_amplitude(float pAmplitude) {
mAmplitude = pAmplitude;
}
float[] wavetable() {
return mWavetable;
}
float process() {
mArrayPtr += mStepSize;
final int i = (int) mArrayPtr;
final float mFrac = mArrayPtr - i;
final int j = i % mWavetable.length;
mArrayPtr = j + mFrac;
return mWavetable[j] * mAmplitude;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ import ddf.minim.*;
import com.jsyn.unitgen.*;


Parameter mParameterAttack;
Parameter mParameterDecay;
Parameter mParameterSustain;
Parameter mParameterRelease;
Slider mSliderAttack;
Slider mSliderDecay;
Slider mSliderSustain;
Slider mSliderRelease;
int mNote;
void settings() {
size(640, 480, P2D);
size(640, 480);
}
void setup() {
hint(DISABLE_KEY_REPEAT);
mParameterAttack = new Parameter();
mParameterDecay = new Parameter();
mParameterSustain = new Parameter();
mParameterSustain.horziontal = false;
mParameterRelease = new Parameter();
mSliderAttack = new Slider();
mSliderDecay = new Slider();
mSliderSustain = new Slider();
mSliderSustain.horziontal = false;
mSliderRelease = new Slider();
updateADSR();
println(Instrument.ADSR_DIAGRAM);
}
Expand All @@ -29,7 +29,7 @@ void draw() {
} else {
background(255);
}
final float mXOffset = (width - Parameter.size * 4) * 0.5f;
final float mXOffset = (width - Slider.size * 4) * 0.5f;
final float mYOffset = height * 0.5f;
translate(mXOffset, mYOffset);
scale(1, -1);
Expand All @@ -47,64 +47,68 @@ void keyReleased() {
Ton.note_off();
}
void drawDiagram() {
stroke(0, 63);
line(0, 0, Parameter.size * 4, 0);
stroke(0);
line(0, 0,
mParameterAttack.current_position_x(),
mParameterAttack.current_position_y());
line(mParameterAttack.current_position_x(),
mParameterAttack.current_position_y(),
mParameterDecay.current_position_x(),
mParameterDecay.current_position_y());
line(mParameterDecay.current_position_x(),
mParameterDecay.current_position_y(),
mParameterSustain.current_position_x(),
mParameterSustain.current_position_y());
line(mParameterSustain.current_position_x(),
mParameterSustain.current_position_y(),
mParameterRelease.current_position_x(),
mParameterRelease.current_position_y());
stroke(0, 15);
line(0, 0, Slider.size * 4, 0);
/* GUI */
noStroke();
fill(0);
ellipse(0, 0, Parameter.radius * 2, Parameter.radius * 2);
mParameterAttack.draw(g);
mParameterDecay.draw(g);
mParameterSustain.draw(g);
mParameterRelease.draw(g);
ellipse(0, 0, Slider.radius, Slider.radius);
mSliderAttack.draw(g);
mSliderDecay.draw(g);
mSliderSustain.draw(g);
mSliderRelease.draw(g);
/* envelope */
strokeWeight(3);
stroke(0);
line(0, 0,
mSliderAttack.current_position_x(),
mSliderAttack.current_position_y());
line(mSliderAttack.current_position_x(),
mSliderAttack.current_position_y(),
mSliderDecay.current_position_x(),
mSliderDecay.current_position_y());
line(mSliderDecay.current_position_x(),
mSliderDecay.current_position_y(),
mSliderSustain.current_position_x(),
mSliderSustain.current_position_y());
line(mSliderSustain.current_position_x(),
mSliderSustain.current_position_y(),
mSliderRelease.current_position_x(),
mSliderRelease.current_position_y());
strokeWeight(1);
}
void updateDiagram(float mXOffset, float mYOffset) {
float mX = mouseX - mXOffset;
float mY = -mouseY + mYOffset;
mParameterAttack.update(mX, mY, mousePressed);
mParameterAttack.x = 0;
mParameterAttack.y = Parameter.size;
mParameterDecay.update(mX, mY, mousePressed);
mParameterDecay.x = mParameterAttack.current_position_x();
mParameterDecay.y = mParameterSustain.current_position_y();
mParameterSustain.update(mX, mY, mousePressed);
mParameterSustain.x = mParameterDecay.current_position_x() + Parameter.size;
mParameterSustain.y = 0;
mParameterRelease.update(mX, mY, mousePressed);
mParameterRelease.x = mParameterSustain.x;
mParameterRelease.y = 0;
mSliderAttack.update(mX, mY, mousePressed);
mSliderAttack.x = 0;
mSliderAttack.y = Slider.size;
mSliderDecay.update(mX, mY, mousePressed);
mSliderDecay.x = mSliderAttack.current_position_x();
mSliderDecay.y = mSliderSustain.current_position_y();
mSliderSustain.update(mX, mY, mousePressed);
mSliderSustain.x = mSliderDecay.current_position_x() + Slider.size;
mSliderSustain.y = 0;
mSliderRelease.update(mX, mY, mousePressed);
mSliderRelease.x = mSliderSustain.x;
mSliderRelease.y = 0;
}
void updateADSR() {
Ton.instrument().attack(mParameterAttack.value);
Ton.instrument().decay(mParameterDecay.value);
Ton.instrument().sustain(mParameterSustain.value);
Ton.instrument().release(mParameterRelease.value);
Ton.instrument().attack(mSliderAttack.value);
Ton.instrument().decay(mSliderDecay.value);
Ton.instrument().sustain(mSliderSustain.value);
Ton.instrument().release(mSliderRelease.value);
}
static class Parameter {
static class Slider {
static final float size = 120;
static final float radius = 6;
static final float radius = 8;
float x;
float y;
float value;
boolean horziontal;
boolean hoover;
boolean drag;
Parameter() {
Slider() {
x = 0;
y = 0;
value = 0.5f;
Expand All @@ -113,19 +117,24 @@ static class Parameter {
drag = false;
}
void draw(PGraphics g) {
// g.stroke(0, 63);
// g.line(x, y, x + (horziontal ? size : 0), y + (horziontal ? 0 : size));
g.stroke(191);
g.line(x, y, x + (horziontal ? size : 0), y + (horziontal ? 0 : size));
final float mEdgeDiameter = 5;
g.noStroke();
g.fill(0);
g.ellipse(x, y, mEdgeDiameter, mEdgeDiameter);
g.ellipse(x + (horziontal ? size : 0), y + (horziontal ? 0 : size), mEdgeDiameter, mEdgeDiameter);
g.noStroke();
g.fill(hoover ? (drag ? 223 : 127) : 0);
g.ellipse(current_position_x(), current_position_y(), radius * 2, radius * 2);
g.fill(0);
g.ellipse(current_position_x(), current_position_y(), radius * (hoover ? 2 : 1), radius * (hoover ? 2 : 1));
}
void update_value(float pX, float pY) {
value = (horziontal ? (pX - x) : (pY - y)) / size;
value = min(1, max(0, value));
}
boolean hit(float pX, float pY) {
final float mDistance = PVector.dist(new PVector().set(pX, pY),
new PVector().set(current_position_x(), current_position_y()));
new PVector().set(current_position_x(), current_position_y()));
return mDistance < radius * 2;
}
float current_position_x() {
Expand Down
Binary file modified processing-library/ton/library/ton.jar
Binary file not shown.
Loading

0 comments on commit 80cd092

Please sign in to comment.