Sammy1Am / MoppyClassic

Moppy has been replaced with Moppy 2.0!
569 stars 190 forks source link

Relay Drum Kit #154

Open sparklini opened 7 years ago

sparklini commented 7 years ago

(After at last getting this on GitHub I realize there might be a less technical way to do this with out a Shift Register, using an additional Arduino.

Take a look anyways and tell me what you think.)

Moppy with Relay Drum Kit

I’ve added a small amount of code that allows Sammy’s Moppy program to output the drum track to other analog devices, specifically relays and contactors.

A relay is an electrical-mechanical switch that uses an electromagnet to activate a switch. (The same function as a transistor).

A little about me before I get into how it works. I’m an electrician, not a programer. For me, the physical part of the Moppy is simple. I learned just enough about JAVA to get this going. (There are a number of options that I decided to leave out to keep the changes as simple as possible to understand. Perhaps someone with better computer skills will offer to make some of the additions.)

The relay drum kit uses only 3 Arduino pins so you can still run 7 disk drives and one relay set of 8 (actually any number. More on this later) relays or contactors. This is done using a 74HC595 or similar shift register and the Arduino function of ShiftOut.

The outputs from the shift register are used to control power MOSFETS (similar to a transistor) which provide the current and voltage needed to drive the relays.

Lucky for us there are tutorials! https://www.arduino.cc/en/tutorial/ShiftOut

There are many for MOSFETs too. Here is one about LED strips. Replace the LED’s with your relays. https://learn.adafruit.com/rgb-led-strips?view=all

Shift registers work on binary outputs, 8 bits at a time. No drum sounds is represented by 00000000 Each of the zeros is associated with a different relay with the first relay being the digit to the right. If I want relay 1 and 3 to activate at the same time I would send this to the shift register. 00000101 If I wanted to smash everything at once. 11111111

Drum sounds are given a value that when converted to binary will only have one “1” and the rest “0”. We get those numbers but doubling. 1, 2, 4, 8, 16, 32, 64, 128 Converting any one of those numbers to Binary and sending it to the shift register will cause 1 relay to activate. Adding any of those numbers together and then converting to Binary will cause multiple relays to activate.

Because a relay makes a “click” sound both with is is powered and again when de energized the program holds each relay in its current state until that relay (or drum) is called again. The Arduino sketch compares the last beat with the current beat and outputs the opposite value for each digit that calls for a drum sound. 10001000 (last beat) 00001111 (input to Arduino) 10000111 (output from Arduino to shift register)

This way we only get one click each time a drum hit happens (off OR on) and not (off AND on).

Shift registers are linkeble so in theory you could hook up many in series and connect more relays but there are only so many different types of clicking sounds you can get so I just stopped at 8. The average drum kit doesn’t get much bigger than that anyway.

One problem I faced was the number of different MIDI drum sounds. Not wanting to set up a relay for each different option I sorted through them and grouped the most common ones. So all kick drums would be given the same relay number because there is usually only one kick drum on a song. Same with all the different types of snares. This worked well more the majority of the songs but not always.

Another option is to assign each drum sound to a relay as the sound occurred. This worked great for insuring that all the sounds got picked up but can result in the ride cymbal being assigned to a giant motor contactor that would just shake the whole table until everything fell apart.

The set up now does a bit of both.

Some input from other users would be great.

TeslaXC commented 6 years ago

I am interested in your idea for implementing the relay drum kit with an additional Arduino, instead of using a shift register. I am also not a programmer by trade, I am an electro-mechanical engineering student, so I admire your resolve in delving into Java. In the meantime, I will take a look at your code to see if I can come up with anything myself!

sparklini commented 6 years ago

Thanks for your interest.

I'm also not a programer (Electrician) but I did get it working perfectly. The shift register worked out really well and freed up a lot of outputs on the Arduino. I suggest not giving up on it too soon.

I don't recall if I ever uploaded my current code. Let me know if you have any questions and I can go back and look at my final effort.

Stephen


From: TeslaXC notifications@github.com Sent: November 12, 2017 4:06 PM To: SammyIAm/Moppy Cc: sparklini; Author Subject: Re: [SammyIAm/Moppy] Relay Drum Kit (#154)

I am interested in your idea for implementing the relay drum kit with an additional Arduino, instead of using a shift register. I am also not a programmer by trade, I am an electro-mechanical engineering student, so I admire your resolve in delving into Java. In the meantime, I will take a look at your code to see if I can come up with anything myself!

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHubhttps://github.com/SammyIAm/Moppy/pull/154#issuecomment-343767702, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AQi1YKdUxNFjuZe95C2HN8F7eYbVRlUvks5s113FgaJpZM4L9yGg.

TeslaXC commented 6 years ago

Hey! I got it working (sort of). I only have a one-channel relay on hand, so I can only listen to one drum part at a time. I have LED's to flash representing the other drum parts. I've used a separate UNO on a second USB input so I may use 8 drives on my original UNO.

Have you run into this problem? Sometimes the drum parts move by too quickly so that the indicator LED on the relay briefly lights, but the armature doesn't engage. Is there a solution for this in the code, or do you think I just have to avoid faster tempos, or re-write the drum part?

Also, I am planning on using a solenoid to strike objects rather than relay clicks, since I don't have access to a wide range of relays. Do you think that the issue of drum hits being too brief would affect the solenoids? I think it's hard to say until I buy them, but I'm leaning towards yes - it would, since it takes time for the plunger of the solenoid to move and strike an object. This would cause the solenoids to "shoot blanks", since the plunger wouldn't be engaged long enough to hit the object.

I'm grateful that you are looking at your project so many months later. Many thanks!!

RedFox1177 commented 6 years ago

A solution for the slow relay is a solid state relay, but I think that the solenoid would be too slow as well.

On Nov 16, 2017 7:32 PM, "TeslaXC" notifications@github.com wrote:

Hey! I got it working (sort of). I only have a one-channel relay on hand, so I can only listen to one drum part at a time. I have LED's to flash representing the other drum parts. I've used a separate UNO on a second USB input so I may use 8 drives on my original UNO.

Have you run into this problem? Sometimes the drum parts move by too quickly so that the indicator LED on the relay briefly lights, but the armature doesn't engage. Is there a solution for this in the code, or do you think I just have to avoid faster tempos, or re-write the drum part?

Also, I am planning on using a solenoid to strike objects rather than relay clicks, since I don't have access to a wide range of relays. Do you think that the issue of drum hits being too brief would affect the solenoids? I think it's hard to say until I buy them, but I'm leaning towards yes - it would, since it takes time for the plunger of the solenoid to move and strike an object. This would cause the solenoids to "shoot blanks", since the plunger wouldn't be engaged long enough to hit the object.

I'm grateful that you are looking at your project so many months later. Many thanks!!

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/SammyIAm/Moppy/pull/154#issuecomment-345108315, or mute the thread https://github.com/notifications/unsubscribe-auth/AHbSeuGlXyj0To3c5f4xXqydoQrr7HiDks5s3NQ2gaJpZM4L9yGg .

Sammy1Am commented 6 years ago

First, @sparklini , I'm sorry I haven't really gotten around to look at merging this code. Just a week or so ago I finally got inspired to start looking into Moppy again, and your relay-drumset sounds awesome, so I'm hoping we get can better support for that available.

With regards to your timing issue, @TeslaXC : The current code responds to note-on and note-off events because for pitched instruments the length of the note is a significant factor. For percussion, drum-rolls aside, the "length" of each hit is more or less irrelevant. Rather than using the note-off event to de-energize the relay, you might want to just have the note-on event put a value in an array, decrement that value each tick, and then switch it off when you hit zero. That'd allow you to tune the length of pulse that best triggers your solenoid (I'm actually planning to work on something with solenoids too over the holidays, so I may end up writing something up myself in the nearish future).

sparklini commented 6 years ago

@TeslaXC , I never had any issues with notes being too short. I think using solenoids is a great idea. You would need to remove the "Latching" part of the code otherwise you will only get contact on every other occurrence.
Looking at the date that I posted the last edit, I've very sure I cleaned it up and made some changes. I will try and upload this weekend.

@RedFox1177, are you suggesting using a SS relay to drive the solenoid? I did use a few of them in my build to drive some contractors that had A/C coils in them. (This is a good time to point out that contactors/relays are available with A/C or D/C coils. When you drive them with the wrong type of current the collapsing magnetic field induces a currenting back into the coil. I burned out a few before I figured this one out.) I used the SS relays to drive my A/C contactos without burning them out.

Thanks @SammyIAm, that sounds correct.

I will get that final code posted ASAP as well as some songs that I edited. I think my final build had 12 floppy drives and 8 relays.

Thanks for your interested in this.

RedFox1177 commented 6 years ago

@sparklini Yes, you could possibly use a solid state relay to drive the solenoid quicker. The issue with that is that I think you’ll run into the issue that the solenoid won’t be able to keep up, and like TeslaXC said, “shoot blanks”. (For the statement above about shift registers, I think there’s a way to use I2C to communicate between Arduino on the analog ports.) Also, did you use flyback diodes when you were driving the relays? Or did you burn out the coil itself?

sparklini commented 6 years ago

Used diodes on the DC relays. Burnt out the coils. See that here https://www.instagram.com/p/BDHj_nilTei/

Sent from my Bell Samsung device over Canada's largest network.

-------- Original message -------- From: RedFox1177 notifications@github.com Date: 2017-11-17 10:29 AM (GMT-05:00) To: SammyIAm/Moppy Moppy@noreply.github.com Cc: sparklini imam_thecomputer@hotmail.com, Mention mention@noreply.github.com Subject: Re: [SammyIAm/Moppy] Relay Drum Kit (#154)

@sparklinihttps://github.com/sparklini Yes, you could possibly use a solid state relay to drive the solenoid quicker. The issue with that is that I think you’ll run into the issue that the solenoid won’t be able to keep up, and like @TeslaXChttps://github.com/teslaxc said, “shoot blanks”. Also, did you use flyback diodes when you were driving the relays? Or did you burn out the coil itself?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/SammyIAm/Moppy/pull/154#issuecomment-345275082, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AQi1YOp1NYGd_ch7WAru0aES-ZpSGFMHks5s3aZtgaJpZM4L9yGg.

sparklini commented 6 years ago

Turns out I didn't take many videos of the final project in action but there is a good example of the drum relays on my instagrahm feed here.

https://www.instagram.com/p/BDHjwNFlTeK/

Sent from my Bell Samsung device over Canada's largest network.

-------- Original message -------- From: TeslaXC notifications@github.com Date: 2017-11-16 7:32 PM (GMT-05:00) To: SammyIAm/Moppy Moppy@noreply.github.com Cc: sparklini imam_thecomputer@hotmail.com, Author author@noreply.github.com Subject: Re: [SammyIAm/Moppy] Relay Drum Kit (#154)

Hey! I got it working (sort of). I only have a one-channel relay on hand, so I can only listen to one drum part at a time. I have LED's to flash representing the other drum parts. I've used a separate UNO on a second USB input so I may use 8 drives on my original UNO.

Have you run into this problem? Sometimes the drum parts move by too quickly so that the indicator LED on the relay briefly lights, but the armature doesn't engage. Is there a solution for this in the code, or do you think I just have to avoid faster tempos, or re-write the drum part?

Also, I am planning on using a solenoid to strike objects rather than relay clicks, since I don't have access to a wide range of relays. Do you think that the issue of drum hits being too brief would affect the solenoids? I think it's hard to say until I buy them, but I'm leaning towards yes - it would, since it takes time for the plunger of the solenoid to move and strike an object. This would cause the solenoids to "shoot blanks", since the plunger wouldn't be engaged long enough to hit the object.

I'm grateful that you are looking at your project so many months later. Many thanks!!

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHubhttps://github.com/SammyIAm/Moppy/pull/154#issuecomment-345108315, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AQi1YPfHdmV5z04GLtXS-DDZi2EzTH_9ks5s3NQ3gaJpZM4L9yGg.

sparklini commented 6 years ago

I think I've found my final edit but I really don't remember how to upload it to GitHub.

I basically learned just enough Java to make the needed changes and once I got it working I started rebuilding a motorcycle.

Can anyone tell me the date upload my edit? I think I have files modified in May 2016. I may need some help getting it uploaded. (I know, I'm ridiculous)

TeslaXC commented 6 years ago

Looks like February 10th, 2017 to me.

I just realized I wasn't running the code changes in the Moppy program, only my second Arduino output. When I went to update the file change in my Moppy program, I can't seem to solve this problem. There is an error caused by lines 116 and line 129 both defining the integer "period". I'm stuck on how to change this, however maybe your updated code will have the fix.

sparklini commented 6 years ago

@TeslaXC looks like Feb 10th is the most recent file I can find too. it seems to run fine for me. I can't figure out how to add it but I will cut and paste the code here. Maybe there is a difference that you can spot? (I wish I understood this better.)

package moppydesk.outputs;

import gnu.io.SerialPort; import javax.sound.midi.MidiMessage;

/*

// New array to handle drum track. Like above, each "note" is listed in the array and a place holder. // The value stored in each spot is an integer that in Biaray contains seven 0's and one 1. // The location of the 1 in the 8 bit byte represents a different shift register output. // For example, if we have a small relay acting as a ride cymbal(1), and a larger one for the snare(2) and a // large motor contactor acting as a kick drum(8). The arduino sketch would output this // - 00000001 (ride) // - 00000010 (snare) // - 00001000 (kick) // and if they all happen on the same beat // - 00001011

// Because there are so many different drum sounds I've pre defined the most common.
// This works well in most situations but not all.
// if the track was writen for Bongos, these values would need adjusting.
// The number should also reflex they size of the relay. (Big relay = kickdrum)
public static int[] microPeriodsDrum = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, //C1 - B1
    4, 8, 16, 16, 16, 64, 1, 64, 2, 8, 2, 128, //C2 - B2
    64, 32, 128, 1, 0, 0, 8, 0, 0, 32, 0, 1, //C3 - B3
    64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //C4 - B4
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

// to keep track of the number of different drums used in the song
private int drumNumber = 1;

/**
 * Maximum number of cents to bend +/-.
 */
private static int BEND_CENTS = 200;

/**
 * Resolution of the Arduino code in microSeconds.
 */
public static int ARDUINO_RESOLUTION = 40;

/**
 * Current period of each MIDI channel (zero is off) as set by the NOTE ON
 * message; for pitch-bending.
 */
private int[] currentPeriod = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

MoppyCOMBridge mb;
SerialPort com;

public MoppyPlayerOutput(MoppyCOMBridge newMb) {
    mb = newMb;
}

public void close() {
    mb.resetDrives();
    mb.close();
}

//Is called by Java MIDI libraries for each MIDI message encountered.
public void send(MidiMessage message, long timeStamp) {
    if (message.getStatus() > 127 && message.getStatus() < 144) { // Note OFF
        //Convert the MIDI channel being used to the controller pin on the
        //Arduino by multipying by 2.
        byte pin = (byte) (2 * (message.getStatus() - 127));

        //System.out.println("Got note OFF on pin: " + (pin & 0xFF));
        mb.sendEvent(pin, 0);
        currentPeriod[message.getStatus() - 128] = 0;
    } else if (message.getStatus() > 143 && message.getStatus() < 160) {// Note ON
        //Convert the MIDI channel being used to the controller pin on the
        //Arduino by multipying by 2.
        byte pin = (byte) (2 * (message.getStatus() - 143));

        //Get note number from MIDI message, and look up the period.
        //NOTE: Java bytes range from -128 to 127, but we need to make them
        //0-255 to use for lookups.  & 0xFF does the trick.

        // After looking up the period, devide by (the Arduino resolution * 2).
        // The Arduino's timer will only tick once per X microseconds based on the
        // resolution.  And each tick will only turn the pin on or off.  So a full
        // on-off cycle (one step on the floppy) is two periods.

        // If drum track - use microPeriodsDrum
        int period = 0;
        //** System.out.println(pin & 0xFF);
        if ((pin & 0xFF) == 20) {
            // This section will assign a relay to each drum sound as they happen.    
            if (microPeriodsDrum[(message.getMessage()[1])] == 0) {
                microPeriodsDrum[(message.getMessage()[1])] = drumNumber;
                System.out.println("Drum Midi value " + (message.getMessage()[1] & 0xff) + " drumNumber " + drumNumber);
                drumNumber = drumNumber * 2;
            }
            period = microPeriodsDrum[(message.getMessage()[1])];
            System.out.println("Drum Midi value " + (message.getMessage()[1] & 0xff) + " will be played by relay " + period);
        } else if ((pin & 0xFF) != 20) {
            // if it is not from the drum track
            period = microPeriods[(message.getMessage()[1] & 0xff)] / (ARDUINO_RESOLUTION * 2);
            // System.out.println("Got note ON on pin: " + (pin & 0xFF) + " with period " + period);         
            //System.out.println(message.getLength() + " " + message.getMessage()[message.getLength()-1]);
        }
        //Zero velocity events turn off the pin.
        if (message.getMessage()[2] == 0) {
            mb.sendEvent(pin, 0);
            currentPeriod[message.getStatus() - 144] = 0;
        } else {
            mb.sendEvent(pin, period);
            currentPeriod[message.getStatus() - 144] = period;
        }
    } else if (message.getStatus()
            > 223 && message.getStatus() < 240) { //Pitch bends
        //Only proceed if the note is on (otherwise, no pitch bending)
        if (currentPeriod[message.getStatus() - 224] != 0) {
        //Convert the MIDI channel being used to the controller pin on the
            //Arduino by multipying by 2.
            byte pin = (byte) (2 * (message.getStatus() - 223));

            double pitchBend = ((message.getMessage()[2] & 0xff) << 7) + (message.getMessage()[1] & 0xff);
            //System.out.println("Pitch bend " + pitchBend); 
            // Calculate the new period based on the desired maximum bend and the current pitchBend value
            int period = (int) (currentPeriod[message.getStatus() - 224] / Math.pow(2.0, (BEND_CENTS / 1200.0) * ((pitchBend - 8192.0) / 8192.0)));
            //System.out.println("Bent by " + Math.pow(2.0, (bendCents/1200.0)*((pitchBend - 8192.0) / 8192.0)));
            mb.sendEvent(pin, period);
        }
    }

}

public void reset() {
    mb.resetDrives();
}

public void silence() {
    mb.silenceDrives();
}

}

TeslaXC commented 6 years ago

I've copied & pasted that code into my Moppy, and it's error-free! There was definitely a difference around lines 116-129. I'm getting my solenoids in the mail tomorrow (ceterus paribus). Looking forward to getting this running. I'll definitely upload the changes I make to make solenoids functional with this project.

Edit: Actually, I've just tried to run the program as is. Getting a lot of errors here. I'll look into it

sparklini commented 6 years ago

@TeslaXC, I always got some sort of error while it was compiling but it always seem to work. Keep me updated.

TeslaXC commented 6 years ago

For me, the errors are not in the compiler, I also got errors in the compiler even with the original Moppy IIRC. Whenever I try to load a MIDI into Moppy, the error I get is "java.lang.UnsupportedOperationException: Not supported yet."

I have a feeling we may have different versions of Moppy, so I'll try to redownload my Moppy to see if that fixes it.

TeslaXC commented 6 years ago

Okay, I've fixed the code that was originally uploaded in the post in my Moppy program. On line 129, the "int" before the period should not be there. After I removed that, it is working as intended! I will look into editing the code for solenoid-capability now.

Chong-McBong commented 6 years ago

i'm a bit late to the party, has this been added yet? i need to add some drums to my setup