Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Smoothing pots. #15

Closed
NikolajRFA opened this issue Dec 25, 2017 · 32 comments
Closed

Smoothing pots. #15

NikolajRFA opened this issue Dec 25, 2017 · 32 comments

Comments

@NikolajRFA
Copy link

Having problems with smoothing a potentiometer, when choosing the hires potentiometer exampe i get signal but it seems rather constant... and i really want single values so i dont loose midi info.

I also had to manually include som librarys it couldn't find when i was trying to compile the code. I dont know why this problem keeps happening. Could it be because i dont have the librarys installed in the default folders.

1 pot

Arduino Leonardo

Schematic: ?

Software versions:

MIDI Controller library: 3.0.0
Arduino IDE: ? 1.8.5
Operating System: Windows
Operating System version: 10
(Teensyduino): ? 1.40 ?
(Encoder library): Where do i find this?
(MIDIUSB library): Where do i find this?

Settings in the IDE

Full code

#include <Encoder.h>

/*
This is an example of the "AnalogHiRes" class of the MIDI_controller library.
Connect a potentiometer to analog pin A0. It will send MIDI Pitch Bend messages on channel 1
Map it in your DAW or DJ software.

Written by Pieter P, 08-09-2017
https://github.com/tttapa/MIDI_controller
*/

#include <MIDI_Controller.h> // Include the library

// Create a new instance of the class 'AnalogHiRes', called 'potentiometer', on pin A0, 
// that sends MIDI Pitch Bend messages on channel 1
AnalogHiRes potentiometer(A0, 1);

void setup() {}

void loop() {
  // Refresh the MIDI controller (check whether the potentiometer's input has changed since last time, if so, send the new value over MIDI)
  MIDI_Controller.refresh();
}

i pretty much just put in the encoder library manually as i was getting errors saying that it couldn't find it.

i want to make a MIDI controller to control my DAW (FL Studio).

@tttapa
Copy link
Owner

tttapa commented Dec 25, 2017

As mentioned in the ReadMe, you have to install the Encoder library (even if you don't use it, because of the way C++ handles dependencies). You shouldn't have to add it at the top of your sketch, however.

Are you sure that FL Studio supports Pitch Bend messages as controls? Have you tried the potentiometer example? It uses Control Change events (which are more widely supported).

@NikolajRFA
Copy link
Author

The MIDI data works fine, my problem is that the Arduino sends duplicate values over MIDI and I would like it to only send one value... I find the potentiometer example to do this, but it is filled with noise and it is jumping back and forth a value.

@tttapa
Copy link
Owner

tttapa commented Dec 27, 2017

That's rather strange, the running average work just fine for me, it does a great job at eliminating the noise.
AnalogHiRes sending duplicate values is weird as well:

if (value != oldVal) // if the value changed since last time

What kind of duplicate values are you getting? Did you use a MIDI monitor?

@NikolajRFA
Copy link
Author

turns out the midi data is just flickering and thereforeit is sending constant messages when i am using the "HiRes-Potentiometer" example.
Is there anyway i can use the library to send a variable value so i can use a library i found to send the values?

@NikolajRFA
Copy link
Author

I see the code you send me isen't the same as i am using...
And i can't get i to work because im missing "analogHiRes.h"

@tttapa
Copy link
Owner

tttapa commented Dec 27, 2017

The code I sent was a snippet from the source code. You don't have to use it yourself.
Do you want to use ResponsiveAnalogRead? In that case, you can easily extend the Analog and AnalogHiRes classes with variants that use that as an alternative to a simple running average. If I find the time, I'll write you an example.

@NikolajRFA
Copy link
Author

that would be nice as i don't know how to extend the classes, i have only been in the Arduino game for a month or so.

@tttapa
Copy link
Owner

tttapa commented Dec 27, 2017

Untested!
Put all three files in the same folder (with the same name as Main.ino).


Main.ino

#include <MIDI_Controller.h> // Include the library
#include "AnalogHiResResponsive.h"

// Create a new instance of the class 'AnalogHiResResponsive', called 'potentiometer', on pin A0, 
// that sends MIDI Pitch Bend messages on channel 1
AnalogHiResResponsive potentiometer(A0, 1);

void setup() {}

void loop() {
  // Refresh the MIDI controller (check whether the potentiometer's input has changed since last time, if so, send the new value over MIDI)
  MIDI_Controller.refresh();
}

AnalogHiResResponsive.h

#ifndef AnalogHiResResponsive_h_
#define AnalogHiResResponsive_h_

#include "Arduino.h"
#include "MIDI_Controller.h"
#include <ResponsiveAnalogRead.h>

class AnalogHiResResponsive : public MIDI_Control_Element
{
  public:
    AnalogHiResResponsive(pin_t analogPin, uint8_t channel); // Constructor
    void map(int (*fn)(int));                        // Change the function pointer for analogMap to a new function. It will be applied to the raw analog input value in Analog::refresh()

  private:
    void refresh(); // Read the analog input value, update the average, map it to a MIDI value, check if it changed since last time, if so, send Pitch Bend message over MIDI

    ResponsiveAnalogRead respAnalog = {0, true};
    pin_t analogPin;
    uint8_t channel;
    int (*analogMap)(int) = identity; // function pointer to identity function f(x) → x

    static int identity(int x) {  // identity function f(x) → x
      return x;
    }
};

#endif // AnalogHiResResponsive_h_

AnalogHiResResponsive.cpp

#include "AnalogHiResResponsive.h"

AnalogHiResResponsive::AnalogHiResResponsive(pin_t analogPin, uint8_t channel) // Constructor
  : analogPin(analogPin), channel(channel) {}

void AnalogHiResResponsive::refresh() // read the analog value, update the average, map it to a MIDI value, check if it changed since last time, if so, send Pitch Bend message over MIDI
{
  ExtIO::analogRead(analogPin); // throw away first analog reading
  analog_t input = ExtIO::analogRead(analogPin);
  uint16_t value = analogMap(input); // apply the analogMap function to the value (identity function f(x) = x by default)
  respAnalog.update(value); // update the responsive analog average

  if (respAnalog.hasChanged()) // if the value changed since last time
  {
    value = respAnalog.getValue(); // get the responsive analog average value
    value = value << 4; // make it a 14-bit number (pad with 4 zeros)
    MIDI_Controller.MIDI()->send(PITCH_BEND, channel + channelOffset * channelsPerBank, value, value >> 7); // send a Pitch Bend MIDI event
  }
}

void AnalogHiResResponsive::map(int (*fn)(int)) {  // change the function pointer for analogMap to a new function. It will be applied to the raw analog input value in refresh()
  analogMap = fn;
}

I just copied the AnalogHiRes.h and AnalogHiRes.cpp source files from the library, renamed the class, changed the includes, deleted the running average functions and variables, added ResponsiveAnalogRead and edited the refresh function to use the responsive analog read average instead of the running average.

@NikolajRFA
Copy link
Author

This works really good. Now i just need to figure out how to program the rest of the controller...
How will this AnalogHiResResponsive work? do i just add that library together with the MIDI_Controller library to get the "AnalogHiResResponsive"?

@NikolajRFA
Copy link
Author

also. How do i adjust it to send messages on other channels not just the pitchbend?

@tttapa
Copy link
Owner

tttapa commented Dec 27, 2017

You don't have to add anything to the library, after you include the header files, you can just use it like the other parts of the library.

You can do the same thing for the Analog class if you need to.
What do you need for the rest of the controller?

@NikolajRFA
Copy link
Author

I wanted to pu a couple of extra potentiometers on and some buttons

@tttapa
Copy link
Owner

tttapa commented Dec 27, 2017

You can add multiple potentiometers by using arrays:

AnalogHiResResponsive potentiometers[] = {
  {A0, 1},
  {A1, 2},
  {A3, 3},
  // etc.
};

For adding buttons, take a look at the buttons example.

@NikolajRFA
Copy link
Author

ohh i see, i will try that.

@NikolajRFA
Copy link
Author

i still dont know how to send data over other channels than Pitch Bend.

@tttapa
Copy link
Owner

tttapa commented Dec 27, 2017

That's what the Analog class is for. It sends the data as Control Change events. You can use it as is (works great for me, YMMV), or you can create a new class that uses the ResponsiveAnalogRead.

@tttapa
Copy link
Owner

tttapa commented Dec 27, 2017

Everything should be in the documentation. If you think something is missing, or not clear enough, feel free to let me know :)

@NikolajRFA
Copy link
Author

im glad you are helping with this, as i still am reallybad coding the arduino.

@NikolajRFA
Copy link
Author

also... what does that "uint8_t" do i am seeing it everywhere that MIDI and arduino is mentioned

@tttapa
Copy link
Owner

tttapa commented Dec 27, 2017

It is a data type. It's an unsigned integer (uint) of 8 bits wide. This means that it can store any value between 0 and 255 (=2^8-1).

@tttapa
Copy link
Owner

tttapa commented Dec 27, 2017

It's used here because MIDI packets are constructed of multiple of these 8-bit bytes.

@NikolajRFA
Copy link
Author

i see

@NikolajRFA
Copy link
Author

NikolajRFA commented Dec 27, 2017

I can't really get it to work by using your library and code... But i tried writing a piece of code with my current knowladge and a bit of googeling, only using the "ResponsiveAnalogRead" and the "MIDIUSB" libraries, and this works

Here is the code if interested.

#include <ResponsiveAnalogRead.h>
#include "MIDIUSB.h"

int val = 0;
int lastVal = 0;

const int Pot = A0;

ResponsiveAnalogRead PotRead(Pot, true);

void setup() {
  Serial.begin(115200);
}

void loop() {
  PotRead.update();

  val = PotRead.getValue()/8;
 

  
  midiEventPacket_t event = {0x0B, 0xB0 | 0, 104, val};
  

  if(val != lastVal)
  {MidiUSB.sendMIDI(event);
   MidiUSB.flush();}
  lastVal = val;
 
}

I have no idea why your library won't work (probably because i am really bad at coding)
the code would probably be better if I could get your library to work...

@tttapa
Copy link
Owner

tttapa commented Dec 28, 2017

Here's what a MIDI controller with potentiometers and buttons would look like using the library:

#include <MIDI_Controller.h> // Include the library
#include "AnalogHiResResponsive.h"

AnalogHiResResponsive hiResPotentiometers[] = { // 10-bit Pitch Bends
  {A0, 1},  // pin A0, MIDI channel 1
  {A1, 2},
  {A2, 3},
  {A3, 4},
};

Analog potentiometers[] = { // 7-bit Control Change
  {A4, 0x20, 1},  // pin A4, controller 0x20, MIDI channel 1
  {A5, 0x21, 1},
};

Digital buttons[] = {  // Note On / Off
  {2, 0x3C, 1},  // pin 2, note 0x3C (middle C), MIDI channel 1
  {3, 0x3D, 1},
  {4, 0x3E, 1},
  {5, 0x3F, 1},
};

void setup() {}

void loop() {
  MIDI_Controller.refresh();
}

You need to have the files "AnalogHiResResponsive.cpp" and "AnalogHiResResponsive.h" in the same folder (press CTRL+SHIFT+N in the IDE, enter the filename "AnalogHiResResponsive.cpp", then paste the code there and save, same for "AnalogHiResResponsive.h").

@NikolajRFA
Copy link
Author

The codes is sendinf pitch bend messages together with my other midi messages when i am turning the potentiometers

@tttapa
Copy link
Owner

tttapa commented Dec 28, 2017

Correct.
If you want 10-bit resolution, you have to use pitch bends (AnalogHiRes and AnalogHiResResponsive). If 7 bit is enough (in most cases it is), you can use control change (Analog). The potentiometers on analog pins A0-A3 send pitch bend messages, the potentiometers connected to pins A4-A5 send control change messages. It's up to you to decide which ones you'd like to use. You can make all of them control change, make all of them pitch bends, or mix and match. You don't have to use pitch bends if you don't want to.
You can add as many potentiometers and buttons to the arrays as you'd like, and you can decide what controller numbers, note numbers, MIDI channels ... they use.

@NikolajRFA
Copy link
Author

after fiddeling a bit with it i have gotten it to work with the stadart "MIDIUSB" library. FL Studio can't reassign pitchbend messages to control other parameters, which i would have needed for it to have worked.

anyways, thanks for the help.

@rabbiccu
Copy link

rabbiccu commented Jun 7, 2018

I think I experienced what this user was talking about. In the examples the channels are different and the CC# is the same. There was crosstalk and the knobs were shaky. When each knob is given its own CC# they become nice and smooth.

/*
This is an example of the "Analog" class of the MIDI_controller library.
Connect a potentiometer to analog pin A0. This will be the MIDI channel volume of channel 1.
Map it in your DAW or DJ software.
Written by Pieter P, 08-09-2017
https://github.com/tttapa/MIDI_controller
*/

#include <MIDI_Controller.h> // Include the library

// Create a new instance of the class 'Analog', called 'potentiometer', on pin A0, 
// that sends MIDI messages with controller 7 (channel volume) on channel 1
Analog potentiometer_A(A0, MIDI_CC::Sound_Controller_1, 1);
Analog potentiometer_B(A1, MIDI_CC::Sound_Controller_2, 1);
Analog potentiometer_C(A2, MIDI_CC::Sound_Controller_3, 1);
Analog potentiometer_D(A3, MIDI_CC::Sound_Controller_4, 1);
Analog potentiometer_E(A4, MIDI_CC::Sound_Controller_5, 1);

void setup() {}

void loop() {
  // Refresh the MIDI controller (check whether the potentiometer's input has changed since last time, if so, send the new value over MIDI)
  MIDI_Controller.refresh();
}

@tttapa
Copy link
Owner

tttapa commented Jun 7, 2018

The master version has significantly improved filtering on the potentiometer inputs. I don't have the time to release it, because updating the documentation takes a lot of work, and I have to level it with the Control Surface library first, but you could consider it as stable for now (1ecbd2c).

You can try git checkout origin/master, or download the master files manually.

@tttapa
Copy link
Owner

tttapa commented Jun 7, 2018

By the way, instead of:

Analog potentiometer_A(A0, MIDI_CC::Sound_Controller_1, 1);
Analog potentiometer_B(A1, MIDI_CC::Sound_Controller_2, 1);
Analog potentiometer_C(A2, MIDI_CC::Sound_Controller_3, 1);
Analog potentiometer_D(A3, MIDI_CC::Sound_Controller_4, 1);
Analog potentiometer_E(A4, MIDI_CC::Sound_Controller_5, 1);

You can do:

Analog potentiometers[] = {
  {A0, MIDI_CC::Sound_Controller_1, 1},
  {A1, MIDI_CC::Sound_Controller_2, 1},
  {A2, MIDI_CC::Sound_Controller_3, 1},
  {A3, MIDI_CC::Sound_Controller_4, 1},
  {A4, MIDI_CC::Sound_Controller_5, 1},
};

@rabbiccu
Copy link

rabbiccu commented Jun 7, 2018

"You can try git checkout origin/master, or download the master files manually."

How exactly do I do that? This is my first project.

@tttapa
Copy link
Owner

tttapa commented Jun 7, 2018

When installing the library, you downloaded a ZIP file from the releases page. Now, instead of using the ZIP from the releases page, download the ZIP from the main page:
image
Make sure to delete the old version before you install the new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants