HELP: Need Arduino coding elves to help complete an Arduino Christmas present

Hi all,

I am an Arduino newbie looking for some help me cross the finish line with a cool project that I am building for my son for Christmas.

I am stuck on some of the code and I am looking for someone who could do this for me for a fee or just for Christmas spirit. I have attached all of the details, but the basic idea is 48 Piezo sensors going (Analog) into the Mayhew Labs Mux Shield attached to the Arduino Mega 2560.

I already have a working 16 input code, but I need to expand it to 48 inputs and then combine it with the Mux Shield code.

Thanks in advance for anyone who can help or refer me to anyone who can help me.

Justin

More attachments,

Justin

Arduino Marimba Project Summary.doc (120 KB)

Arduino_Marimba_Script_11_4_2015_16_Channel.txt (5.77 KB)

Mux_Shield1.txt (3.19 KB)

Here are the images attached to the top post. Now people don't have to download them to view the images.

Here's a link to instructions on how to insert an uploaded image into a post (for next time).

Are you planning to generate MIDI output based on the inputs?

I'm curious about the project but to be honest, I'm not curious enough to want to download the documents. I may not be the only one who doesn't want to have to download files to find out details of the project. It might be a good idea to post some of the more important parts of the contents of the document.

Hi DuaneDegn,

Thanks for the information on posting pictures properly.

Yes eventually I will be going Direct MIDI out, but for now I am just going out USB Serial to my Mac and using a Midi Converter Application to get the signal into Garage Band. All of that is currently working.

Here is a summary of the my project:

Hardware
Arduino Mega 2560

Mayhew Labs 48 Channel MUX Shield

Project Summary

Phase 1 (Building the environment with only 16 channels)
• All physical woodwork completed
• Attached 16 Piezo Sensors to with parallel 1M Resisters to Arduino Mega 2560 Analog Inputs/ground
• Attached Arduino Mega 2560 to Mac Desktop into Garage Band using the USB Serial Cable and converting the Midi using the “Hairless Midi” application
• Installed the Arduino code: Arduino_Marimba_Script_11_4_2015.rtf (attached)
Result: Successful - 16 Keys trigger properly into Garage Band

Phase 2 (Expanding to 48 Channels using the Mayhew Labs MUX Shield)
• Mayhew labs provides the sample code for 48 Analog inputs (See attached code)
• Attached 48 keys to MUX Shield Analog Inputs with parallel 1M Resisters. *
• Attached remaining 10 unused Analog inputs on Arduino Mega to ground *
• (See diagram. The green is where the MUX connects to the Mega)
• I have tried integrating the MUX Shield code with the original code without much success, primarily because I simply do not know what I am doing :smiling_face:
Result: Unsuccessful - I am looking to hire or find someone who can expand my 16 channel code into 48 channel code, and also integrate the Mux Shield Code.

Thanks,

Justin

I likely missed something as without the hardware in question it's impossible to test, but here is something you should be able use as a starting point.

I've encoded your many separate arrays into bit-field encode 32 Bit values within an anonymous struct.

// <http://forum.arduino.cc/index.php?topic=366478.0>

#define COUNT_ENTRIES(ARRAY)        (sizeof(ARRAY) / sizeof(ARRAY[0]))

const uint8_t   pinCONTROL0    = 5;
const uint8_t   pinCONTROL1    = 4;
const uint8_t   pinCONTROL2    = 3;
const uint8_t   pinCONTROL3    = 2;

struct pad_t
{
    uint32_t    active      :  1; //  1 false/true
    uint32_t    note        :  7; //  8 0 - 127
    uint32_t    velocity    :  7; // 18 0 - 127
    uint32_t    play_time   :  7; // 25 0 - 127
    uint32_t    play_timeMAX:  7; // 32 0 - 127
};

struct pad_t    pads[][3] =
{
    //   ADC0                      ADC1                       ADC2

      { { false, 51, 50, 0, 90 }, { false, 67, 50, 0, 90 }, { false, 83, 50, 0, 90 } } // PAD  15, 31, 47
    , { { false, 50, 50, 0, 90 }, { false, 66, 50, 0, 90 }, { false, 82, 50, 0, 90 } } // PAD  14, 30, 46
    , { { false, 49, 50, 0, 90 }, { false, 65, 50, 0, 90 }, { false, 81, 50, 0, 90 } } // PAD  13, 29, 45
    , { { false, 48, 50, 0, 90 }, { false, 64, 50, 0, 90 }, { false, 80, 50, 0, 90 } } // PAD  12, 28, 44
    , { { false, 47, 50, 0, 90 }, { false, 63, 50, 0, 90 }, { false, 79, 50, 0, 90 } } // PAD  11, 27, 43
    , { { false, 46, 50, 0, 90 }, { false, 62, 50, 0, 90 }, { false, 78, 50, 0, 90 } } // PAD  10, 26, 42
    , { { false, 45, 50, 0, 90 }, { false, 61, 50, 0, 90 }, { false, 77, 50, 0, 90 } } // PAD   9, 25, 41
    , { { false, 44, 50, 0, 90 }, { false, 60, 50, 0, 90 }, { false, 76, 50, 0, 90 } } // PAD   8, 24, 40
    , { { false, 43, 50, 0, 90 }, { false, 59, 50, 0, 90 }, { false, 75, 50, 0, 90 } } // PAD   7, 23, 39
    , { { false, 42, 50, 0, 90 }, { false, 58, 50, 0, 90 }, { false, 74, 50, 0, 90 } } // PAD   6, 22, 38
    , { { false, 41, 50, 0, 90 }, { false, 57, 50, 0, 90 }, { false, 73, 50, 0, 90 } } // PAD   5, 21, 37
    , { { false, 40, 50, 0, 90 }, { false, 56, 50, 0, 90 }, { false, 72, 50, 0, 90 } } // PAD   4, 20, 36
    , { { false, 39, 50, 0, 90 }, { false, 55, 50, 0, 90 }, { false, 71, 50, 0, 90 } } // PAD   3, 19, 35
    , { { false, 38, 50, 0, 90 }, { false, 54, 50, 0, 90 }, { false, 70, 50, 0, 90 } } // PAD   2, 18, 34
    , { { false, 37, 50, 0, 90 }, { false, 53, 50, 0, 90 }, { false, 69, 50, 0, 90 } } // PAD   1, 17, 33
    , { { false, 36, 50, 0, 90 }, { false, 52, 50, 0, 90 }, { false, 68, 50, 0, 90 } } // PAD   0, 16, 32
};

// MIDI channel from 0 to 15 ( 1-16 in "real world")
const uint8_t   MIDI_CHANNEL    = 1;

// Velocity ON (true) or OFF (false)
bool            fVelocity   = true;

void midi_send(uint8_t midi_message, uint8_t pitch, uint8_t midi_velocity)
{
    Serial.write(midi_message << 4 | MIDI_CHANNEL); // BYTE 1
    Serial.write(pitch);                            // BYTE 2
    Serial.write(midi_velocity);                    // BYTE 3
}

void do_channel(uint8_t const pinADC, struct pad_t& pad)
{
    int velocity = map(analogRead(pinADC), 0, 1023, 0, 127)
    if ( velocity > pad.velocity )
    {
        if ( ! pad.active )
        {
            pad.active      = true;
            pad.play_time   = 0;

            // NOTE ON, WITH VELOCITY
            midi_send(0x1001, pad.note, velocity);
        }
        else
        {
            ++pad.play_time;
        }
    }
    else if ( pad.active )
    {
        if ( ++pad.play_time > pad.play_timeMAX )
        {
            pad.active = false;

            // NOTE ON, NO VELOCITY
            midi_send(0x1001, pad.note, 0);
        }
    }
}

void loop()
{
    const int ROWS      = COUNT_ENTRIES(pads);
    const int COLUMNS   = COUNT_ENTRIES(pads[0]);

    for ( size_t iROW = 0; iROW < ROWS; iROW++ )
    {
        // ... MULTIPLEX SELECTOR ...
        digitalWrite(pinCONTROL0, (iROW & 0x1111) >> 3);
        digitalWrite(pinCONTROL1, (iROW & 0x0111) >> 2);
        digitalWrite(pinCONTROL2, (iROW & 0x0011) >> 1);
        digitalWrite(pinCONTROL3, (iROW & 0x0001) >> 0);


        // ... 3 CHANNELS A0, A1 and A2 ...
        const uint8_t   pinsADC[COLUMNS] = { A0, A1, A2 };

        for ( size_t iCOLUMN = 0; iCOLUMN < COLUMNS; iCOLUMN++ )
        {
            do_channel(pinsADC[iCOLUMN], pads[iROW][iCOLUMN]);
        }
    }
}

void setup()
{
    pinMode(pinCONTROL0, OUTPUT);
    pinMode(pinCONTROL1, OUTPUT);
    pinMode(pinCONTROL2, OUTPUT);
    pinMode(pinCONTROL3, OUTPUT);

    Serial.begin(115200);
}

Thanks SO much for taking the time to try something.
I will try this code tomorrow morning to see what happens.

Thanks!

Justin

Hi lloyddean,

So tried installing the code this morning and here are the results.
First, I received an error (See attachment) and I added a ; to fix it. (See attachment)
I just followed the instructions but do not know why that was needed.

Once the code was installed, it seems that multiple notes are being triggered and they don't correspond to the 4 octaves of the marimba.

I attached the image to show what the hairless Midi app sees when a single note is played.
I also attached an audio file of the marimba being played with this code. (Please ignore my kids birds chirping in the background)

Thanks!

Justin

Hairless_Midi_Trigger.JPG

Marimba_Test.mp4.zip (94.4 KB)

Hello Justin,

Sorry about the missing semi-colon. I see it missing in my post above as well which I find odd because the file here has it. Something happened, somewhere, somehow, between my copy from the source into the post. But the good thing is it was and easy fix!

As to the notes being played I made no attempt to map MIDI notes to corresponding channels and simply duplicated your 16 mappings to the other 32 multiplexed channels, so no surprise there.

Other than those quibbles do you have enough to proceed?
Any questions?

Lloyd

justinmenzel1:
Hi lloyddean,

So tried installing the code this morning and here are the results.
First, I received an error (See attachment) and I added a ; to fix it. (See attachment)
I just followed the instructions but do not know why that was needed.

Once the code was installed, it seems that multiple notes are being triggered and they don't correspond to the 4 octaves of the marimba.

justinmenzel1:
I already have a working 16 input code, but I need to expand it to 48 inputs and then combine it with the Mux Shield code.

Can you make a class for 1 input and then make an array of 48 of those ... maybe in PROGMEM?
The class would wrap the Mux Shield interface and input together as objects.

Hello Justin,

I see that the section to turn of the midi note was somehow copied from the note on code.

Try downloading the updated code from the post above, try it a and let me know.

There is the issue of logic channel numbering vs code channel numbering. When you specified -

const uint8_t MIDI_CHANNEL = 1;

Di you mean MIDI channel 1 or MIDI channel 2?

Hi lloyddean,

First of all, I can not thank you enough for helping me out with this. I definitely owe you some favors.
Here is where I am at.

The revised code gave me all kinds of errors and would not trigger any notes whatsoever.
I think that it had something to do with the Serial.write(midi_message<< 4 | MIDI_CHANNEL); // BYTE 1
line of code.

In any case, I went back to the original one you provided, and I updated the mappings from 36-83 and here is the result.

Here is the code:

// <http://forum.arduino.cc/index.php?topic=366478.0>

#define COUNT_ENTRIES(ARRAY)        (sizeof(ARRAY) / sizeof(ARRAY[0]))

const uint8_t   pinCONTROL0    = 5;
const uint8_t   pinCONTROL1    = 4;
const uint8_t   pinCONTROL2    = 3;
const uint8_t   pinCONTROL3    = 2;

struct pad_t
{
 uint32_t    active      :  1; //  1 false/true
 uint32_t    note        :  7; //  8 0 - 127
 uint32_t    velocity    : 10; // 18 0 - 1023
 uint32_t    play_time   :  7; // 25 0 - 127
 uint32_t    play_timeMAX:  7; // 32 0 - 127
};

struct pad_t    pads[][3] =
{
 //   ADC0                      ADC1                       ADC2

   { { false, 51, 400, 0, 90 }, { false, 67, 400, 0, 90 }, { false, 83, 400, 0, 90 } } // PAD  15, 31, 47
 , { { false, 50, 400, 0, 90 }, { false, 66, 400, 0, 90 }, { false, 82, 400, 0, 90 } } // PAD  14, 30, 46
 , { { false, 49, 400, 0, 90 }, { false, 65, 400, 0, 90 }, { false, 81, 400, 0, 90 } } // PAD  13, 29, 45
 , { { false, 48, 400, 0, 90 }, { false, 64, 400, 0, 90 }, { false, 80, 400, 0, 90 } } // PAD  12, 28, 44
 , { { false, 47, 400, 0, 90 }, { false, 63, 400, 0, 90 }, { false, 79, 400, 0, 90 } } // PAD  11, 27, 43
 , { { false, 46, 400, 0, 90 }, { false, 62, 400, 0, 90 }, { false, 78, 400, 0, 90 } } // PAD  10, 26, 42
 , { { false, 45, 400, 0, 90 }, { false, 61, 400, 0, 90 }, { false, 77, 400, 0, 90 } } // PAD   9, 25, 41
 , { { false, 44, 400, 0, 90 }, { false, 60, 400, 0, 90 }, { false, 76, 400, 0, 90 } } // PAD   8, 24, 40
 , { { false, 43, 400, 0, 90 }, { false, 59, 400, 0, 90 }, { false, 75, 400, 0, 90 } } // PAD   7, 23, 39
 , { { false, 42, 400, 0, 90 }, { false, 58, 400, 0, 90 }, { false, 74, 400, 0, 90 } } // PAD   6, 22, 38
 , { { false, 41, 400, 0, 90 }, { false, 57, 400, 0, 90 }, { false, 73, 400, 0, 90 } } // PAD   5, 21, 37
 , { { false, 40, 400, 0, 90 }, { false, 56, 400, 0, 90 }, { false, 72, 400, 0, 90 } } // PAD   4, 20, 36
 , { { false, 39, 400, 0, 90 }, { false, 55, 400, 0, 90 }, { false, 71, 400, 0, 90 } } // PAD   3, 19, 35
 , { { false, 38, 400, 0, 90 }, { false, 54, 400, 0, 90 }, { false, 70, 400, 0, 90 } } // PAD   2, 18, 34
 , { { false, 37, 400, 0, 90 }, { false, 53, 400, 0, 90 }, { false, 69, 400, 0, 90 } } // PAD   1, 17, 33
 , { { false, 36, 400, 0, 90 }, { false, 52, 400, 0, 90 }, { false, 68, 400, 0, 90 } } // PAD   0, 16, 32
};

// MIDI channel from 0 to 15 ( 1-16 in "real world")
const uint8_t   MIDI_CHANNEL    = 0;

// Velocity ON (true) or OFF (false)
bool            fVelocity   = true;

void midi_send(uint8_t midi_message, uint8_t pitch, uint8_t midi_velocity)
{
 Serial.write(midi_message + MIDI_CHANNEL);
 Serial.write(pitch);
 Serial.write(midi_velocity);
}

void do_channel(uint8_t const pinADC, struct pad_t& pad)
{
 int velocity = analogRead(pinADC);

 if ( velocity > pad.velocity )
 {
     if ( ! pad.active )
     {
         pad.active      = true;
         pad.play_time   = 0;

         velocity        = fVelocity ? ((velocity / 8) - 1) : 127;

         midi_send(144, pad.note, velocity)
     ;}
     else
     {
         ++pad.play_time;
     }
 }
 else if ( pad.active )
 {
     if ( ++pad.play_time > pad.play_timeMAX )
     {
         pad.active = false;

         midi_send(144, pad.note, 0);
     }
 }
}

void loop()
{
 const int ROWS      = COUNT_ENTRIES(pads);
 const int COLUMNS   = COUNT_ENTRIES(pads[0]);

 for ( size_t iROW = 0; iROW < ROWS; iROW++ )
 {
     // ... MULTIPLEX SELECTOR ...
//        digitalWrite(pinCONTROL0, (iROW & 0x1111) >> 3);
//        digitalWrite(pinCONTROL1, (iROW & 0x0111) >> 2);
//        digitalWrite(pinCONTROL2, (iROW & 0x0011) >> 1);
//        digitalWrite(pinCONTROL3, (iROW & 0x0001) >> 0);
     digitalWrite(pinCONTROL0, (iROW&15)>>3);
     digitalWrite(pinCONTROL1, (iROW&7)>>2);
     digitalWrite(pinCONTROL2, (iROW&3)>>1);
     digitalWrite(pinCONTROL3, (iROW&1));

     // ... 3 CHANNELS A0, A1 and A2 ...
     const uint8_t   pinsADC[COLUMNS] = { A0, A1, A2 };

     for ( size_t iCOLUMN = 0; iCOLUMN < COLUMNS; iCOLUMN++ )
     {
         do_channel(pinsADC[iCOLUMN], pads[iROW][iCOLUMN]);
     }
 }
}

void setup()
{
 pinMode(pinCONTROL0, OUTPUT);
 pinMode(pinCONTROL1, OUTPUT);
 pinMode(pinCONTROL2, OUTPUT);
 pinMode(pinCONTROL3, OUTPUT);

 Serial.begin(115200);
}

When played softly, all the notes play properly. However they play a lot more than one note when played at a normal strength amount. I know that you are thinking that the Piezo discs are triggering each other somehow, but I have proven that is not the case by isolating a single disc, which still triggers multiple notes and incorrect notes when played harder.

Anyway, I think that this is my last hurdle here. I am certain that something in the code is causing the triggering of multiple notes being played when a single Piezo is pressed hard, but I just don't know what it is.

Thanks for all your help here!!!!

Justin

moderator added code tags

Changed the code above, please try it!

lloyddean,

I just wanted to thank you again for all your help with this project! It is people like you that make a lot of these projects possible for newbies like me. As an update to this project, I never could get the Mayhew Labs MUX Shield to work properly, but I got everything working properly by simply using (3) Mega 2560s.
The 48 Midi Marimba looks and sounds great, and is being played every day.

Thanks again!

Justin

Justin,

Hoping you see this late response and can help a fellow newbie. If not I'll post a new thread. I've built a 48 Midi Marimba with 3 Mega 2560s. I'm having an awful time trying to connect them to my Mac OS 10.10. I can get each to work individually. But just can't seem to figure out how to get all three devices to read at the same time. Apple's Audio MIDI Setup with it's Aggregate Device or Multi-output device look promising. But I can't get the Arduinos to register as a USB Audio device. I've been exploring FTDI drivers, but am unsure if this is the issue. Thanks for any help you can lend! I really appreciate it!

Rob