-
Notifications
You must be signed in to change notification settings - Fork 140
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
Implement Velocity with NoteButton #283
Comments
The NoteButton class has a You could then do something like this: #include <Control_Surface.h>
// Instantiate a MIDI Interface to use
HairlessMIDI_Interface midi;
// Instantiate a Transposer that can transpose from one octave down to one
// octave up
Transposer<-12, +12> transposer;
// Instantiate a Selector to change the transposition
IncrementDecrementSelector<transposer.getNumberOfBanks()> selector = {
transposer,
{10, 11},
Wrap::Wrap,
};
// Instantiate some multiplexers
CD74HC4067 mux0 = {
A0, // Input pin
{2, 3, 4, 5} // Address pins S0, S1, S2, S3
},
mux1 = {
A1, // Input pin
{2, 3, 4, 5} // Address pins S0, S1, S2, S3
};
using namespace MIDI_Notes;
Bankable::NoteButtons<32> buttons = {
transposer, // Bank/Transposer configuration
copyAs<Button>(cat(mux0.pins(), mux1.pins())), // Button pins
{note(C, 2), CHANNEL_1}, // Base address
{1, 0}, // Increment note by 1 semitone, don't increment channel
};
// 7-bit filtered analog input for velocity control
FilteredAnalog<7> velocityInput = A2;
// Initialize the Control Surface
void setup() {
Control_Surface.begin();
}
// Update the Control Surface
void loop() {
if (velocityInput.update())
buttons.setVelocity(velocityInput.getValue());
Control_Surface.loop();
} Instead of writing out all multiplexer pins, you can use: cat(mux0.pins(), mux1.pins()) The copyAs<Button>(...) |
Nice. Thanks! Regarding the velocity. I think it's a good start, but I'm not planning to have a separated input to define the velocity, but each pin (sensor) attached to multiplexers will define that. I was thinking that I could calculate the time spent to run the interval from 1023 to 0 of each sensor. Then determine the velocity (0 ~ 127) based on a "magic" constant. |
Apologies, I misunderstood your question. In that case, defining your own MIDI Output Element (like some of the code discussed in #151) would definitely be the best solution. I can't really help you with the code that actually reads and interprets the measurements from the proximity sensors, but if you need help with the boilerplate code around it, to make it work with the library, sending MIDI, etc. feel free to ask questions about it here. I think the best approach would be to start from the Custom-MIDI-Output-Element example. Once you understand how it works, you should be able to replace the digital You'll probably have to keep a running average of the past velocities (the velocity as measured by the sensor, not MIDI velocity), wait for it to reach a certain threshold and then wait until the velocity decreases below some second threshold. Then you can send a MIDI note on message. You can then use the maximum velocity (the highest velocity before it started decreasing) to compute the MIDI velocity. Once you have something working, making your custom class "Bankable" isn't hard to do, I can help you with that once you get there. |
Don't worry... You've provided me some documentation and now I know how to start. That's great. I'll keep this issue opened. |
Hi @tttapa I think I already have a daft to perform what I want to implement. This is what I have so far... From
From
This implementation is really far from what I would expect to calculate the velocity but it's a good draft (I mean it minimally works).
So, is there any template/example/documentation explaining how to make this kind of class |
To make it bankable, you use the I've added an example here: https://tttapa.github.io/Control-Surface-doc/Doxygen/d4/d6b/Custom-MIDI-Output-Element-Bankable_8ino-example.html To support more than one button, you can have a look at the implementation of |
@tttapa , I've tried so many different ways to implement the code but I don't know exactly how to implement it (some limitions on C++)... I'm using this code as example to implement multiple sensors: As far as I understood, coinsidering that I'm using a sensor with analog ports, and not template <uint8_t NumSensors>
class NoteSensitiveKeys : public MIDIOutputElement {
public:
NoteSensitiveKeys(const Array<AH::FilteredAnalog<>???, NumSensors> &sensors,
const MIDIAddress &baseAddress,
const RelativeMIDIAddress &incrementAddress)
: sensors{sensors}, baseAddress(baseAddress),
incrementAddress(incrementAddress) {}
(...)
private:
Array<AH::FilteredAnalog<7>???, NumSensors> sensors;
const MIDIAddress baseAddress;
const RelativeMIDIAddress incrementAddress;
}; I could not find any example on how to use multiple analog ports. That's why I'm asking you... |
It's not entirely clear to me what your question is. If you want to use the For example (using Control Change instead of notes so I don't have to worry about note on/off): #include <Control_Surface.h>
template <uint8_t NumSensors>
class NoteSensitiveKeys : public MIDIOutputElement {
public:
NoteSensitiveKeys(const Array<AH::FilteredAnalog<7>, NumSensors> &sensors,
const MIDIAddress &baseAddress,
const RelativeMIDIAddress &incrementAddress)
: sensors{sensors}, baseAddress(baseAddress),
incrementAddress(incrementAddress) {}
void begin() override {}
void update() override {
MIDIAddress address = baseAddress;
for (auto &sensor : sensors) {
if (sensor.update())
Control_Surface.sendCC(address, sensor.getValue());
address += incrementAddress;
}
}
private:
Array<AH::FilteredAnalog<7>, NumSensors> sensors;
const MIDIAddress baseAddress;
const RelativeMIDIAddress incrementAddress;
};
USBDebugMIDI_Interface midi;
NoteSensitiveKeys<4> keys = {
{A0, A1, A2, A3}, // sensors
{0x10, CHANNEL_1}, // base address
{0, 1}, // increment address
};
void setup() {
Control_Surface.begin();
}
void loop() {
Control_Surface.loop();
} |
See also: |
Indeed, I was not so clear in my question (my bad!). But you could respond part of it already. I'm working with some multiplexers I've tried this approach: #include <Arduino_Helpers.h>
#include <AH/Hardware/ExtendedInputOutput/AnalogMultiplex.hpp>
#include <AH/Hardware/FilteredAnalog.hpp>
#include <AH/STL/iterator> // std::back_inserter
#include <AH/STL/vector> // std::vector
auto filteredAnalogs = [] {
auto pins = mux.pins();
std::vector<FilteredAnalog<>> v;
v.reserve(pins.length);
std::copy(std::begin(pins), std::end(pins), std::back_inserter(v));
return v;
}(); // This is an immediately invoked lambda expression from here: https://tttapa.github.io/Control-Surface-doc/Doxygen/d2/d96/3_8FilteredAnalogReadSerial_8ino-example.html
So, how could I convert multiple multiplexers (and respective pins) to be used with this class |
You get this error because you're using an old compiler. Please upgrade the Arduino AVR Core to at least version 1.8.1. I've never really used PlatformIO, so I can't help you with that. |
By the way, Control-Surface/src/AH/Hardware/Button.hpp Lines 18 to 27 in 21a0938
Either way, you cannot pass a |
I've got the anwswer for this issue. It builds now! To update the compiler version just add the configuration Using it in [env:megaatmega2560]
platform = atmelavr
board = megaatmega2560
framework = arduino
lib_deps =
tttapa/Control Surface@^1.2.0-4
paulstoffregen/Encoder@^1.4.1
platform_packages =
toolchain-atmelavr@~1.70300.191015 More details about this configuration can be found here: https://docs.platformio.org/en/latest/projectconf/section_env_platform.html#platform-packages |
Thanks for sharing your solution! |
I implemented this approach class FilteredAnalog
: public GenericFilteredAnalog<AnalogType (*)(AnalogType), Precision,
FilterShiftFactor, FilterType, AnalogType,
IncRes> {
public:
/**
* @brief Construct a new Button object.
*
* **This constructor should not be used.**
* It is just a way to easily create arrays of buttons, and initializing
* them later.
*/
FilteredAnalog()
: GenericFilteredAnalog<AnalogType (*)(AnalogType), Precision,
FilterShiftFactor, FilterType, AnalogType,
IncRes>(NO_PIN, nullptr, 0) {}
(...) and it seems to be working fine. I just need to make some changes in my initial code in order to handle multiple pins in the loop, But I have questions... Is there any reason you didn't implement the constructor with no arguments for |
You can do this without repetitions by using a delegating constructor: FilteredAnalog() : FilteredAnalog(NO_PIN) {}
Because there was no need for it, and because it would be confusing: creating a FilteredAnalog object without specifying a pin is pretty useless in most cases. (The same goes for Buttons, but I did need arrays of buttons, so I added a default constructor.) |
I updated the constructor. Makes sense. Tks I got your point. In this case, I'll just fork |
I'll add a default constructor later today, it's not too big of a change, and having arrays of FilteredAnalog could be useful. |
Nice. If you want I can open a pull request of it. |
The Arduino Helpers library is a separate repository, so I'll have to sync these libraries myself. |
See f440780. (Not yet merged into master.) |
Sounds really great! Thanks for working on this. |
Merged. |
Hi,
First of all congrats for the excellent work on this library!!! This is amazing...
Talking about my question:
I want to implement velocity in project but I still don't have a clue how to do that.
I've already tried to find an answer to my question in any old issue already submitted but I could only find this issue as something similar to what I need: #151. And I don't know exactly how to adapt to my project.
Currently, I'm using
TCRT5000 Infrared Sensor Module
to trigger each note. BTW, it works perfectly with the following code.In the analog pin (
A0
) I get a variation of1023 ~ 0
based on the distance of any object and the sensor.Could you help me with that? Do you have any example I could use to implement that using
Bankable::NoteButton
?Thank you very much!
The text was updated successfully, but these errors were encountered: