How to implement an ADSR as a class? Having trouble...
in
Contributed Library Questions
•
7 months ago
Hi all. I am making an audio wave sequencer as part of an audio programming module at Uni.
Any help of comments or feedback of good or bad kind welcome.
I am using ControlP5 for the sequencer matrix (16x16) which plays notes according to the position of the matrix pointer and the placement of blocks in the matrix. I want to implement an ADSR on the waveforms. I am using the Minim library and the sine, square, saw and noise functions.
I can't use Ugens because there is a problem with Ugens and processing 2.07 on the Uni computers so I want to write a class of an ADSR (envelope generator) with Attack, decay, sustain and release controls to give more dynamism to the sounds.
I have only just started using processing so am a noob although I have some programming experience using Arduino and am concurrently learning VHDL.
I have included my code which is very messy at the moment and the example of the ADSR class is only a half arsed attempt at the moment.. The sequencer works but I can't work out how I could implement an envelope generator as an object. Has anyone attempted this before??
If so, I would love some pointers....
The code for the sequencer and the ADSR class are below:
- import controlP5.*;
- import ddf.minim.*;
- import ddf.minim.signals.*; // new code
- import ddf.minim.effects.*; // new code
- //import ddf.minim.ugens.*;
- import rwmidi.*;
- ControlP5 gui; // new controlP5 gui instance called"gui"
- ControlWindow controlWindow;
- Dong[][] d;
- public int temp=200;
- int tem;
- int note;
- // public float maxamp,attack,decay,sustain,release;
- int nx = 16; // x co-ord cells
- int ny = 16; // y co-ord cells
- float god; // public var for control outside of ....function
- float fref;
- float pref;
- float p;
- Minim minim; // new minim instance called "minim"
- ADSR my_ADSR;
- Knob maxA,att,dec,sus,rel; // ADSR controls
- MidiInput input; // new Midiinput instance called "input"
- MidiOutput output2; // new Midioutput instance called "output"
- ListBox l; // new controlP5 menubox called "l"
- Knob Freq; // new controlP5 Knob instance called Freq (controls pitch of wave
- Knob Amp;
- Knob tempo;
- Slider lpfSlider; // slider for low pass cutoff
- Slider bpfSlider; // slider for band pass cutoff
- Slider bpfBW ; //slider for band pass bandwidth
- LowPassFS lpf;
- BandPass bpf;
- WhiteNoise noise; // new minim instance of white noise called "noise"
- SquareWave sqr1; // new minim instance of squarewave called "sqr1"
- SawWave saw ; // new minim instance of sawwave called "saw"
- SineWave sine; // new minim instance of sinewave called "sine"
- AudioOutput out; // new minim instance of audio output called "out"
- boolean noise_is_on = false; /* boolean cases for waves. not used yet.
- boolean sqr_is_on = false;
- boolean saw_is_on = false;
- boolean sine_is_on = false;
- */
- void setup() {
- size(1200, 700);
- minim = new Minim(this); // "minim" is a new call to open minim for use
- out = minim.getLineOut(Minim.STEREO); // declaration of out as minims' line out for audio
- gui = new ControlP5(this); // declaration of gui as controlP5s' gui for use
- ADSR my_ADSR = new ADSR();
- // gui.printPublicMethodsFor(Matrix.class);
- // gui.printPublicMethodsFor(Matrix.class);
- gui.addMatrix("myMatrix")
- .setPosition(50, 100)
- .setSize(600, 400)
- .setGrid(nx, ny)
- .setGap(10, 2)
- .setInterval(temp)
- .setMode(ControlP5.MULTIPLES)
- .setColorBackground(color(120))
- .setBackground(color(40))
- ;
- gui.getController("myMatrix").getCaptionLabel().alignX(CENTER);
- d = new Dong[nx][ny];
- for (int x = 0;x<nx;x++) {
- for (int y = 0;y<ny;y++) {
- d[x][y] = new Dong();
- }
- }
- noStroke();
- smooth();
- lpfSlider=gui.addSlider("LPCutoff",60.0,7000.0,800,135,20,130);
- bpfSlider=gui.addSlider("BPCutoff",60.0,200.0,850,135,20,130);
- bpfBW=gui.addSlider("BPBandWidth",0.0,250.0,900,135,20,130);
- tempo=gui.addKnob("Tempo",1.0,300.0,860,350,60);
- maxA=gui.addKnob("MaxAmp",0.0,1.0,700,500,60);
- att=gui.addKnob("Attackx",0.0,1000,780,500,60);
- dec=gui.addKnob("Decay",0.0,1000,860,500,60);
- sus=gui.addKnob("Sustain",0.0,1000,940,500,60);
- rel=gui.addKnob("Release",0.0,1000,1020,500,60);
- Freq= gui.addKnob ("Pitch",0.0,5000,0,700,350,60); //name of knob and parameters
- Amp = gui.addKnob ("Amplitude",0.0,1.0,0,780,350,60); // amplitude knob
- Freq.setViewStyle(2); // set the style of knob marker to ellipse
- Amp.setViewStyle(2); // set amp knob style same as above
- Freq.setTickMarkLength(5); // set start and end lines on knob graphic
- Amp.setTickMarkLength(5);
- sine = new SineWave(440, 0.5, out.sampleRate()); // set sine as a new sine wave and set output frequency, amplitude and size
- noise = new WhiteNoise(0.5); // set noise as a white noise with amplitude of 0.5
- sqr1= new SquareWave(220,0.5,out.sampleRate()); // sqr1 setup
- saw= new SawWave(330,0.5,out.sampleRate()); // saw setup
- lpf = new LowPassFS(60,out.sampleRate());
- bpf = new BandPass(700,20,out.sampleRate());
- input = RWMidi.getInputDevices()[0].createInput(this); // set up ins and outs for MIDI
- output2 = RWMidi.getOutputDevices()[0].createOutput();
- l = gui.addListBox("Wave Selector") /* set parameters for the menu box */
- .setPosition(50, 15)
- .setSize(170, 170)
- .setItemHeight(15)
- .setBarHeight(15)
- .setColorBackground(color(0))
- .setColorActive(color(129))
- .setColorForeground(color(0, 100,0))
- ;
- l.captionLabel().toUpperCase(true);
- l.captionLabel().set("Wave Select");
- l.captionLabel().setColor(0x11ff0000);
- l.captionLabel().style().marginTop = 3;
- l.valueLabel().style().marginTop = 3;
- ListBoxItem lbi = l.addItem("Off",1);
- ListBoxItem lbi1 = l.addItem("SineWave",2);
- ListBoxItem lbi2 = l.addItem("SquareWave",3);
- ListBoxItem lbi3 = l.addItem("SawWave",4);
- ListBoxItem lbi4 = l.addItem("WhiteNoise",5);
- lbi.setColorBackground(0xffff0000);
- out.addSignal(sine);
- out.disableSignal(sine);
- out.addSignal(sqr1);
- out.disableSignal(sqr1);
- out.addSignal(saw);
- out.disableSignal(saw);
- out.addSignal(noise);
- out.disableSignal(noise);
- out.addEffect(lpf);
- out.addEffect(bpf);
- }
- void controlEvent(ControlEvent theEvent) {
- // ListBox is if type ControlGroup.
- // 1 controlEvent will be executed, where the event
- // originates from a ControlGroup. therefore
- // you need to check the Event with
- // if (theEvent.isGroup())
- // to avoid an error message from controlP5.
- if (theEvent.isGroup()) {
- // an event from a group e.g. scrollList
- // println(theEvent.group().value()+" from "+theEvent.group());
- if (theEvent.group().value() == 1) {
- out.disableSignal(sine);
- out.disableSignal(saw);
- out.disableSignal(sqr1);
- out.disableSignal(noise);
- }
- if (theEvent.group().value() == 2) {
- out.enableSignal(sine);
- out.disableSignal(saw);
- out.disableSignal(sqr1);
- out.disableSignal(noise);
- }
- if (theEvent.group().value() == 3) {
- out.enableSignal(sqr1);
- out.disableSignal(sine);
- out.disableSignal(saw);
- out.disableSignal(noise);
- }
- if (theEvent.group().value() == 4) {
- out.enableSignal(saw);
- out.disableSignal(sqr1);
- out.disableSignal(noise);
- out.disableSignal(sine);
- }
- if (theEvent.group().value() == 5) {
- out.enableSignal(noise);
- out.disableSignal(saw);
- out.disableSignal(sqr1);
- out.disableSignal(sine);
- }
- }
- if(theEvent.isGroup() && theEvent.name().equals("Wave Select")){
- int test = (int)theEvent.group().value();
- // println("test "+test);
- }
- }
- void draw() {
- background(0,3,20);
- // scroll the scroll List according to the mouseX position
- // when holding down SPACE.
- if (keyPressed && key==' ') {
- //l.scroll(mouseX/((float)width)); // scroll taks values between 0 and 1
- }
- if (keyPressed && key==' ') {
- l.setWidth(mouseX);
- }
- pushMatrix();
- translate(width/2 + 150, height/2);
- rotate(frameCount*0.001);
- for (int x = 0;x<nx;x++) {
- for (int y = 0;y<ny;y++) {
- //float r=random(x*20); // color for graphics-not used here
- //fill(r,r,r); // see above
- //d[x][y].display();
- // println(y);
- }
- }
- popMatrix();
- }
- void myMatrix(int theX, int theY) {
- d[theX][theY].update();
- int note=theY;
- switch(note)
- {
- case 0:
- note=208;
- break;
- case 1:
- note=220; // A3
- break;
- case 2:
- note=233; //A#3
- break;
- case 3:
- note=247; // B3
- break;
- case 4:
- note=262; //c4
- break;
- case 5:
- note=278; //c#4
- break;
- case 6:
- note=294; //D4
- break;
- case 7:
- note=311; // D#4
- break;
- case 8:
- note=330; //E4
- break;
- case 9:
- note=349; // F4
- break;
- case 10:
- note=370; // F#4
- break;
- case 11:
- note=392; // G4
- break;
- case 12:
- note=415; // G#4
- break;
- case 13:
- note=440; //A4
- break;
- case 14:
- note=466; //A#4;
- break;
- case 15:
- note=494; //B4
- break;
- case 16:
- note=523; // C5
- break;
- }
- out.enableSignal(saw);
- out.enableSignal(sqr1);
- saw.setFreq(note/2);
- sqr1.setFreq(note);
- }
- public float Pitch(float freqVal)
- {
- sine.setFreq(freqVal);
- saw.setFreq(freqVal);
- sqr1.setFreq(freqVal);
- god=freqVal;
- return freqVal;
- }
- void Amplitude(float amp)
- {
- sine.setAmp(amp);
- sqr1.setAmp(amp);
- saw.setAmp(amp);
- noise.setAmp(amp);
- }
- void Tempo(int time)
- {
- gui.get(Matrix.class, "myMatrix").setInterval(time);
- }
- void Attackx(int attackVal)
- {
- // my_ADSR.attack_time=attackVal;
- my_ADSR.setattack();
- println("attack"+attackVal);
- }
- void Decay (float decayVal)
- {
- my_ADSR.decay_time=decayVal;
- }
- void Sustain(float sustainVal)
- {
- my_ADSR.sustain_level=sustainVal;
- }
- void Release (float releaseVal)
- {
- my_ADSR.release_time=releaseVal;
- }
- void LPCutoff(float lCut)
- {
- lpf.setFreq(lCut*2);
- }
- void BPCutoff(float bcut)
- {
- bpf.setFreq(bcut);
- }
- void BPBandWidth(float bbw)
- {
- bpf.setBandWidth(bbw);
- }
- /* void controllerChangeReceived(Controller control){
- int x=control.getValue();
- int y=control.getCC();
- int z=control.getValue();
- println(control.getCC());
- println(control.getValue());
- }
- */
- void sysexReceived(rwmidi.SysexMessage msg) {
- // println("sysex " + msg);
- }
- void noteOnReceived(Note note) {
- int v= note.getPitch();
- // println("note on " + note.getPitch());
- out.enableSignal(saw);
- if (v==45)
- out.enableSignal(sqr1);
- }
- void controllerChangeReceived(rwmidi.Controller controller){
- int x=controller.getValue();
- int y=controller.getCC();
- int z=controller.getValue();
- // println(controller.getCC());
- // println(controller.getValue());
- if (y==102)
- {
- map(x,0,127,0,500);
- //Freq.setValue(x*10);
- bpf.setFreq(x*10);
- if ((x*10)<=60)
- {
- x=6;
- }
- // println("bpf="+x*10);
- }
- if (y==105)
- {
- map(z,0,127,0,1000);
- Freq.setValue(x*30);
- sine.setFreq(x*30);
- }
- }
- void keyPressed()
- {
- if (key=='0')
- {
- gui.get(Matrix.class,"myMatrix").clear();
- }
- if (key=='p')
- {
- gui.get(Matrix.class,"myMatrix").pause();
- out.disableSignal(sqr1);
- out.disableSignal(saw);
- if (mousePressed)
- out.enableSignal(sqr1);
- sqr1.setFreq(note);
- //out.disableSignal(sqr1);
- }
- if(key=='s')
- {
- gui.get(Matrix.class,"myMatrix").play();
- out.enableSignal(sqr1);
- out.disableSignal(saw);
- }
- }
- class Dong {
- float x, y;
- float s0, s1;
- Dong() {
- float f= random(-PI, PI);
- x = cos(f)*random(100, 150);
- y = sin(f)*random(100, 150);
- s0 = random(2, 10);
- }
- /* void display() {
- s1 += (s0-s1)*0.1;
- rect(x, y, s1, s1);
- }*/
- void update() {
- s1 = 50;
- }
- void mousePressed()
- {
- }
- }
The start of the ADSR class is below:
- class ADSR
- {
- int attack_time;
- float decay_time;
- float sustain_level;
- float release_time;
- ADSR () {
- attack_time=50;
- decay_time=70;
- sustain_level=0.5;
- release_time=500;
- }
- void setattack()
- {
- delay(attack_time/4);
- sqr1.setAmp(0.1);
- delay(attack_time/4);
- sqr1.setAmp(0.2);
- delay(attack_time/4);
- sqr1.setAmp(0.4);
- delay(attack_time/4);
- sqr1.setAmp(0.6);
- }
- }
Any help of comments or feedback of good or bad kind welcome.
Cheers!!
Steve.
1