Closed JohnnyReggae closed 5 years ago
I have figured it out and is clearly a very noob mistake.
switchOctave.set(map(controlPots[2].getValue(), 0, 124, 15, 0));
I have only defined 9 banks, 0 to 8. Mapping a value even if it wasn't greater than 8 seemed to cause quite a crash. That's why this worked: switchOctave.set(3); for eg.
So I guess my next question is, what should I be using as a selector for changing banks if I am using a potentiometer as my physical selector ? So that I don't programatically make these simple mistakes of setting out of bounds values :-)
Also, is there a way to have the change of channel banks affect both the midi notes channel and the effect channel ? So when changing the midi channel the midi notes travel with the midi cc to the next channel ?
When you try to select a non-existent setting, you get an error. The on-board LED should start blinking in that case, and if you enable debugging in src/Settings/Settings.hpp
, it'll print the error message:
[static CS::setting_t CS::Selectable<N>::validateSetting(CS::setting_t) [with unsigned char N = 9; CS::setting_t = unsigned char] @ line 24]: Error: Setting 9 is not less than the number of settings (9) (0xFFFE)
So I guess my next question is, what should I be using as a selector for changing banks if I am using a potentiometer as my physical selector ? So that I don't programatically make these simple mistakes of setting out of bounds values :-)
Compile-time checking is done by specifying the number of settings as a template parameter (between the <>
). You could create your own class for potentiometer selectors, and make it a template, so it can only be combined with a bank with the same number of settings.
This is the code I used for testing your code, by the way:
#include <Control_Surface.h> // Include the Control Surface library
USBMIDI_Interface midi; // Instantiate a MIDI Interface to use
Bank<9> channelBank(1);
FilteredAnalog<7> controlPot = A2;
void setup() {
Control_Surface.begin(); // Setup the Control Surface
Serial.begin(115200); // Setup Serial output
}
void loop() {
if (controlPot.update()) {
uint8_t setting = map(controlPot.getValue(), 0, 124, 0, 15);
Serial.println(setting);
channelBank.select(setting);
}
Control_Surface.loop();
}
Also, is there a way to have the change of channel banks affect both the midi notes channel and the effect channel ? So when changing the midi channel the midi notes travel with the midi cc to the next channel ?
No, this is not supported at the moment.
Thanks so much for the help, I do appreciate it. I will attempt to create a potentiometer selector class using one of the existing classes as a basis to work from. I'm not overly confident at this point but I'm willing to give it a go. Thanks for the pointers.
Is it possible to create another bank selector to change channels on the midi notes so that there is a bank to change the octave and a bank to change the midi channel ?
I think something like this would work:
#define protected public // Forgive me, Father :(
#include <Control_Surface.h>
BEGIN_CS_NAMESPACE
namespace Bankable {
class TwoBanks {
public:
TwoBanks(OutputBankConfig config1, OutputBankConfig config2,
MIDICNChannelAddress address)
: bankable1{config1}, bankable2{config2}, address(address) {}
void lock() {
bankable1.lock();
bankable2.lock();
}
void unlock() {
bankable1.unlock();
bankable2.unlock();
}
MIDICNChannelAddress getBaseAddress() const { return address; }
MIDICNChannelAddress getActiveAddress() const {
return getBaseAddress()
+ bankable1.getAddressOffset()
+ bankable2.getAddressOffset();
}
private:
BankableMIDIOutput bankable1;
BankableMIDIOutput bankable2;
MIDICNChannelAddress address;
};
class TwoBanksNoteButton : public MIDIButton<TwoBanks, DigitalNoteSender> {
public:
TwoBanksNoteButton(const OutputBankConfig &config1,
const OutputBankConfig &config2,
pin_t pin,
const MIDICNChannelAddress &address,
const DigitalNoteSender &sender = {})
: MIDIButton<TwoBanks, DigitalNoteSender>{
{config1, config2, address}, pin, sender} {}
};
} // namespace Bankable
END_CS_NAMESPACE
USBDebugMIDI_Interface midi;
Bank<16> channelBank(1);
Bank<9> pitchBank(12);
using namespace MIDI_Notes;
Bankable::TwoBanksNoteButton button = {
{channelBank, CHANGE_CHANNEL},
{pitchBank, CHANGE_ADDRESS},
2, // pin
note(C, 0), // address
};
void setup() {
Control_Surface.begin();
channelBank.select(CHANNEL_10.getRaw());
pitchBank.select(4);
}
void loop() {
Control_Surface.loop();
}
Wow, that was quick. You have really given me a lot to go through and use. Again I really do appreciate your time and help.
I will be looking into attempting to create the potentiometer selector class.
Great work on this library it really has saved me a lot of work and time in trying to figure things out myself :-)
This seems to work:
#include <Control_Surface.h>
USBMIDI_Interface midi;
MAX7219SevenSegmentDisplay display = {10}; // MAX7219 connected to SPI bus, load pin to pin 10
template <setting_t N>
class PotSelector : public Updatable<> {
public:
PotSelector(Selectable<N> &selectable, pin_t analogPin, uint8_t displayPosition = 0)
: selectable(selectable), pot{analogPin}, displayPosition(displayPosition) {}
void begin() override {}
void update() override {
if (pot.update()) {
setting_t setting = map(pot.getValue(), 0, 64, 0, N);
selectable.select(setting);
static_assert(N <= 16, "Can only display 0-15");
display.printHex(displayPosition, setting);
}
}
private:
Selectable<N> &selectable;
FilteredAnalog<6, 3, 3> pot; // tweak filter and bit depth if necessary
uint8_t displayPosition;
};
Bank<9> pitchBank(12);
Bank<16> channelBank(1);
PotSelector<9> pitchSel = {
pitchBank, A2, 0,
};
PotSelector<16> channelSel = {
channelBank, A3, 7,
};
void setup() {
display.begin();
Control_Surface.begin();
}
void loop() {
Control_Surface.loop();
}
I added the printHex method in the latest commit: d8471baf2071ff756a05659d91dd0da283cb8501, so you might have to update.
Pieter, you are a scholar and a gentleman ... thank you :-) You have helped immensely. I will try this out today. I am a few steps closer to having everything that I need working.
Your code for the TwoBanksNoteButton works perfectly and for now I can manipulate the banks using an Increment selector setting the banks manually reading from the pots. I started looking into the potSelector code and seeing how I can use that.
My last thing to figure out is to create banks of effects that I can apply to a group of slide potentiometers. eg.
Bank 1 = Reverb, Chorus, Tremelo, Phaser Bank 2 = Pitchbend, Modulation, Breath, Portamento Bank 3 = Release, Attack, Cutoff, Variation etc ...
I'm not sure I understand what you mean. Does each effect have a certain CC number?
Yes they would have their own Midi CC number except for Pitch Bend which seems to be on it's own. So the banks would look like this with midi cc:
Bank 1 = 91, 93, 92, 95 Bank 2 = ??, 1, 2, 5 Bank 3 = 72, 73, 74, 70
I'm not sure how many banks I could come up with, but grouping together certain effects that are related to each other in some way could give me a few more.
So for eg. when bank 1 is selected the 4 slide potentiometers are assigned Reverb, Chorus, Tremolo and Phaser. Bank 2 they get assigned Modulation, Breath, Portamento ... etc.
Okay, I see. For the normal CC numbers, you can use Bankable::ManyAddresses:CCPotentiometer
. I didn't add any examples yet, but maybe you can figure it out from the documentation: https://tttapa.github.io/Control-Surface/Doc/Doxygen/d5/d71/classBankable_1_1ManyAddresses_1_1CCPotentiometer.html
If I have time tonight, I'll try to add an example.
For the pitch bend, you'll have to check the bank setting, disable the CCPotentiometer, and enable the PBPotentiometer when appropriate. They have enable()
and disable()
methods, and you can call getSelection()
on the Bank, IIRC.
If you get stuck, just let me know, and I'll try to look into it tonight.
Turns out you don't even need enable
and disable
, you can just specify an invalid address, so that it won't send anything.
See the example I added in 4bddc91.
Pieter, your code works perfectly. Exactly what I needed to get done. Using the bankable ManyAddresses works exactly like you described and a simple copy/paste of your example code is doing the job.
Thank you again for your time and effort in helping out with this. I really do appreciate it. I now need to put everything into a box so I can bash the buttons proper, as a friend said to me today. :-)
Glad I could help :-)
Created an include file to take your class definition for TwoBanks out of the main code. I don't have my project with me at work today so can't test if it works correctly however it seems to compile ok after adding the files to my Project directory. Not sure if I've done it correctly, but when I added the include #include "TwoBanks.h" while the original code was there the compiler did complain about a redeclaration, so I assume it had included it correctly.
TwoBanks.cpp
#ifdef TEST_COMPILE_ALL_HEADERS_SEPARATELY
#include "TwoBanks.h"
#endif
TwoBanks.h
#pragma once
#include <MIDI_Outputs/Abstract/MIDIButton.hpp>
#include <MIDI_Senders/DigitalNoteSender.hpp>
BEGIN_CS_NAMESPACE
namespace Bankable {
class TwoBanks {
public:
TwoBanks(OutputBankConfig config1, OutputBankConfig config2,
MIDICNChannelAddress address)
: bankable1{config1}, bankable2{config2}, address(address) {}
void lock() {
bankable1.lock();
bankable2.lock();
}
void unlock() {
bankable1.unlock();
bankable2.unlock();
}
MIDICNChannelAddress getBaseAddress() const { return address; }
MIDICNChannelAddress getActiveAddress() const {
return getBaseAddress()
+ bankable1.getAddressOffset()
+ bankable2.getAddressOffset();
}
private:
BankableMIDIOutput bankable1;
BankableMIDIOutput bankable2;
MIDICNChannelAddress address;
};
class TwoBanksNoteButton : public MIDIButton<TwoBanks, DigitalNoteSender> {
public:
TwoBanksNoteButton(const OutputBankConfig &config1,
const OutputBankConfig &config2,
pin_t pin,
const MIDICNChannelAddress &address,
const DigitalNoteSender &sender = {})
: MIDIButton<TwoBanks, DigitalNoteSender>{
{config1, config2, address}, pin, sender} {}
};
} // namespace Bankable
END_CS_NAMESPACE
Managed to test it all this evening, and it works perfectly just including the .h file in my project directory :-)
Great, glad to hear!
Thanks for all the help :-)
Pieter, thank you for an awesome library and just what I need at the moment for my little project of building a midi controller. Please excuse the questions as I am not a developer. I can understand some programming languages when I read through them slowly but get quite lost in the more technical source code.
I have defined 2 banks, 1 to control the octave being played by a group of NoteButtons, and 1 to control the active midi channel. Octave bank is linked to an Increment/Decrement selector and works perfectly. Channel bank also linked to an Increment/Decrement selector that I'm connecting to pin13 to use as an object holder for the banks. I am successfully using the results from turning a potentiometer to set the active midi channel. So both banks work 100%. My problem is that I would like to use a pot as well to change the octave bank. Doing what I did with the other bank does not work however. In fact nothing works if I set the value of the bank using a variable. I can statically change the bank to a value using an actual int. The code uploads but nothing works, as in there are no midi signals going out and my 7 segment led display does not come on.
I'm pretty sure I'm not using the selectors as they are meant to be, but as mentioned I'm not a developer so I cut and paste a lot, and I work from examples to see how to use certain functions etc, and sometimes I can get what the source is trying to tell me.
I cannot for the life of me figure out what is different between the 2 banks where one would allow me to programatically set the bank and the other causes the entire system not to function ?
Apologies for the very lengthy post...