├── LICENSE ├── README.md ├── docs ├── Mackie Control MIDI Map.pdf ├── Motorized Fader Control.fzz ├── mfcbreadboard.pdf └── mfcschematic.pdf ├── fadercontrol └── fadercontrol.pde └── midicontrol └── midicontrol.pde /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Cody Hazelwood 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Motorized Fader and MIDI Control Project 2 | 3 | Code, schematics, and helpful MIDI spec for these projects: 4 | 5 | - [Motorized Faders and the Arduino](http://blog.codyhazelwood.me/motorized-faders-and-the-arduino/) 6 | - [MIDI Control with an Arduino and a Motorized Fader](http://blog.codyhazelwood.me/midi-control-with-an-arduino-and-a-motorized-fader/) 7 | 8 | These projects were completed for my Computer Science Microcontrollers class at Middle Tennessee State University in 2012. Refer to the links above for more information. 9 | -------------------------------------------------------------------------------- /docs/Mackie Control MIDI Map.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codyhazelwood/motorized-fader-arduino/67539e6b66435e0a82bb8891c7f06141c6f1e6a6/docs/Mackie Control MIDI Map.pdf -------------------------------------------------------------------------------- /docs/Motorized Fader Control.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codyhazelwood/motorized-fader-arduino/67539e6b66435e0a82bb8891c7f06141c6f1e6a6/docs/Motorized Fader Control.fzz -------------------------------------------------------------------------------- /docs/mfcbreadboard.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codyhazelwood/motorized-fader-arduino/67539e6b66435e0a82bb8891c7f06141c6f1e6a6/docs/mfcbreadboard.pdf -------------------------------------------------------------------------------- /docs/mfcschematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codyhazelwood/motorized-fader-arduino/67539e6b66435e0a82bb8891c7f06141c6f1e6a6/docs/mfcschematic.pdf -------------------------------------------------------------------------------- /fadercontrol/fadercontrol.pde: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------- 2 | * Programmer: Cody Hazelwood 3 | * Date: March 20, 2012 4 | * Platform: Arduino Uno 5 | * Description: Calibrates a motorized fader's max and min 6 | * position. Allows changing the position with an 7 | * external potentiometer. Uses a capacitance 8 | * sensing circuit for touch sensitivity. 9 | * More or less a proof of concept to be used in a future 10 | * project. 11 | * Dependencies: CapSense Arduino Library (for fader touch sensitivity) 12 | * http://www.arduino.cc/playground/Main/CapSense 13 | * ----------------------------------------------------------------------- 14 | * Copyright (c) 2012 Cody Hazelwood 15 | * 16 | * Permission is hereby granted, free of charge, to any person obtaining a copy 17 | * of this software and associated documentation files (the "Software"), to deal 18 | * in the Software without restriction, including without limitation the rights 19 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 | * copies of the Software, and to permit persons to whom the Software is 21 | * furnished to do so, subject to the following conditions: 22 | * 23 | * The above copyright notice and this permission notice shall be included in 24 | * all copies or substantial portions of the Software. 25 | * 26 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 31 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 32 | * IN THE SOFTWARE. 33 | * ----------------------------------------------------------------------- 34 | */ 35 | 36 | #include //Library for fader touch sensitivity 37 | 38 | //Arduino Pin Assignments 39 | const int motorDown = 3; //H-Bridge control to make the motor go down 40 | const int motorUp = 5; //H-Bridge control to make the motor go up 41 | 42 | //Inputs 43 | const int wiper = 0; //Position of fader relative to GND (Analog 0) 44 | const int pot = 3; //Potentiometer to set position of fader (Analog 3) 45 | const int touchSend = 7; //Send pin for Capacitance Sensing Circuit (Digital 7) 46 | const int touchReceive = 8; //Receive pin for Capacitance Sensing Circuit (Digital 8) 47 | 48 | //Variables 49 | double faderMax = 0; //Value read by fader's maximum position (0-1023) 50 | double faderMin = 0; //Value read by fader's minimum position (0-1023) 51 | 52 | CapSense touchLine = CapSense(touchSend, touchReceive); 53 | 54 | volatile bool touched = false; //Is the fader currently being touched? 55 | 56 | void setup() { 57 | pinMode (motorUp, OUTPUT); 58 | pinMode (motorDown, OUTPUT); 59 | 60 | calibrateFader(); 61 | } 62 | 63 | void loop() { 64 | int state = analogRead(pot); //Read the state of the potentiometer 65 | checkTouch(); //Checks to see if the fader is being touched 66 | 67 | if (state < analogRead(wiper) - 10 && state > faderMin && !touched) { 68 | digitalWrite(motorDown, HIGH); 69 | while (state < analogRead(wiper) - 10 && !touched) {}; //Loops until motor is done moving 70 | digitalWrite(motorDown, LOW); 71 | } 72 | else if (state > analogRead(wiper) + 10 && state < faderMax && !touched) { 73 | digitalWrite(motorUp, HIGH); 74 | while (state > analogRead(wiper) + 10 && !touched) {}; //Loops until motor is done moving 75 | digitalWrite(motorUp, LOW); 76 | } 77 | } 78 | 79 | //Calibrates the min and max position of the fader 80 | void calibrateFader() { 81 | //Send fader to the top and read max position 82 | digitalWrite(motorUp, HIGH); 83 | delay(250); 84 | digitalWrite(motorUp, LOW); 85 | faderMax = analogRead(wiper); 86 | 87 | //Send fader to the bottom and read max position 88 | digitalWrite(motorDown, HIGH); 89 | delay(250); 90 | digitalWrite(motorDown, LOW); 91 | faderMin = analogRead(wiper); 92 | } 93 | 94 | //Check to see if the fader is being touched 95 | void checkTouch() { 96 | touched = touchLine.capSense(30) > 700; //700 is arbitrary and may need to be changed 97 | //depending on the fader cap used (if any). 98 | } 99 | -------------------------------------------------------------------------------- /midicontrol/midicontrol.pde: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------------------------- 2 | * Programmer: Cody Hazelwood 3 | * Date: May 17, 2012 4 | * Platform: Arduino Uno 5 | * Description: MIDI controller using a motorized fader and an Arduino 6 | * Dependencies: CapSense Arduino Library (for fader touch sensitivity) 7 | * http://www.arduino.cc/playground/Main/CapSense 8 | * MIDI Library for Arduino 9 | * http://www.arduino.cc/playground/Main/MIDILibrary 10 | * ----------------------------------------------------------------------- 11 | * Copyright (c) 2012 Cody Hazelwood 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 29 | * IN THE SOFTWARE. 30 | * ----------------------------------------------------------------------- 31 | * ----------------------------------------------------------------------- 32 | */ 33 | 34 | /************************************************************************ 35 | * Currently known issues: 36 | * 37 | * * Only DAW Channels 1-8 work right now 38 | * * Better Fader Calibration is needed 39 | * * Doesn't work with Pro Tools due to Avid's restrictions (but any 40 | * other DAW that supports Mackie Control without HUI support will 41 | * work fine (Cubase, Logic, Digital Performer, Live, etc.) 42 | * 43 | *************************************************************************/ 44 | 45 | #include //Library for fader touch sensitivity 46 | #include //Library for receiving MIDI messages 47 | 48 | //Arduino Pin Assignments 49 | const int motorDown = 5; //H-Bridge control to make the motor go down 50 | const int motorUp = 6; //H-Bridge control to make the motor go up 51 | 52 | //Inputs 53 | const int wiper = 0; //Position of fader relative to GND (Analog 0) 54 | const int touchSend = 7; //Send pin for Capacitance Sensing Circuit (Digital 7) 55 | const int touchReceive = 8; //Receive pin for Capacitance Sensing Circuit (Digital 8) 56 | 57 | //Variables 58 | double faderMax = 0; //Value read by fader's maximum position (0-1023) 59 | double faderMin = 0; //Value read by fader's minimum position (0-1023) 60 | int faderChannel = 1; //Value from 1-8 61 | bool touched = false; //Is the fader currently being touched? 62 | bool positionUpdated = false; //Since touching, has the MIDI position been updated? 63 | 64 | CapSense touchLine = CapSense(touchSend, touchReceive); 65 | 66 | void setup() { 67 | MIDI.begin(MIDI_CHANNEL_OMNI); //Receive messages on all MIDI channels 68 | MIDI.turnThruOff(); //We don't need MIDI through for this 69 | 70 | pinMode (motorUp, OUTPUT); 71 | pinMode (motorDown, OUTPUT); 72 | 73 | calibrateFader(); 74 | 75 | attachInterrupt(0, nextChannel, RISING); 76 | attachInterrupt(1, prevChannel, RISING); 77 | } 78 | 79 | void loop() { 80 | /* If there is a MIDI message waiting, and it is for the currently selected 81 | fader, and it is a PitchBend message (used for fader control), then convert 82 | the PitchBend value and update the fader's current position. */ 83 | if (MIDI.read() && MIDI.getChannel() == faderChannel && MIDI.getType() == PitchBend ) { 84 | /* Bitwise math to take two 7 bit values for the PitchBend and convert to 85 | a single 14 bit value. Then converts it to value between 0 and 1023 86 | to control the fader. */ 87 | int value = (((MIDI.getData2() << 7) + MIDI.getData1()) * 0.0625); 88 | updateFader(value); 89 | } 90 | 91 | checkTouch(); //Checks to see if the fader is being touched 92 | 93 | //If the fader has been touched, it needs to update the position on the MIDI host 94 | if (!positionUpdated) { 95 | updateFaderMidi(); 96 | positionUpdated = true; 97 | } 98 | } 99 | 100 | void updateFaderMidi() { 101 | int velocity = faderPosition(); 102 | byte channelData = 0xE0 + (faderChannel - 1); 103 | // MIDI Message: 104 | Serial.write(channelData); // E(PitchBend) Channel (0-9) 105 | Serial.write(velocity & 0x7F); // Least Sig Bits of Data 106 | Serial.write((velocity >> 7) & 0x7F); // Most Sig Bits of Data 107 | } 108 | 109 | //Calibrates the min and max position of the fader 110 | void calibrateFader() { 111 | //Send fader to the top and read max position 112 | digitalWrite(motorUp, HIGH); 113 | delay(250); 114 | digitalWrite(motorUp, LOW); 115 | faderMax = analogRead(wiper) - 5; 116 | 117 | //Send fader to the bottom and read min position 118 | digitalWrite(motorDown, HIGH); 119 | delay(250); 120 | digitalWrite(motorDown, LOW); 121 | faderMin = analogRead(wiper) + 5; 122 | } 123 | 124 | //Returns a MIDI pitch bend value for the fader's current position 125 | //Cases ensure that there is a -infinity (min) and max value despite possible math error 126 | int faderPosition() { 127 | int position = analogRead(wiper); 128 | int returnValue = 0; 129 | 130 | if (position <= faderMin) { 131 | returnValue = 0; 132 | } 133 | else if (position >= faderMax) { 134 | returnValue = 16383; 135 | } 136 | else { 137 | returnValue = ((float)(position - faderMin) / (faderMax - faderMin)) * 16383; 138 | } 139 | 140 | return returnValue; 141 | } 142 | 143 | //Check to see if the fader is being touched 144 | void checkTouch() { 145 | //For the capSense comparison below, 146 | //700 is arbitrary and may need to be changed 147 | //depending on the fader cap used (if any). 148 | 149 | if (!touched && touchLine.capSense(30) >= 700) { 150 | touched = true; 151 | 152 | //Send MIDI Touch On Message 153 | Serial.write(0x90); 154 | Serial.write(0x67 + faderChannel); 155 | Serial.write(0x7f); 156 | } 157 | else if (touched && touchLine.capSense(30) < 700) { 158 | touched = false; 159 | 160 | //Send MIDI Touch Off Message 161 | Serial.write(0x90); 162 | Serial.write(0x67 + faderChannel); 163 | Serial.write((byte) 0x00); 164 | } 165 | 166 | if (touched) { 167 | positionUpdated = false; 168 | } 169 | } 170 | 171 | //Function to move fader to a specific position between 0-1023 if it's not already there 172 | void updateFader(int position) { 173 | if (position < analogRead(wiper) - 10 && position > faderMin && !touched) { 174 | digitalWrite(motorDown, HIGH); 175 | while (position < analogRead(wiper) - 10 && !touched) {}; //Loops until motor is done moving 176 | digitalWrite(motorDown, LOW); 177 | } 178 | else if (position > analogRead(wiper) + 10 && position < faderMax && !touched) { 179 | digitalWrite(motorUp, HIGH); 180 | while (position > analogRead(wiper) + 10 && !touched) {}; //Loops until motor is done moving 181 | digitalWrite(motorUp, LOW); 182 | } 183 | } 184 | 185 | //Selects the next channel in the DAW 186 | void nextChannel() { 187 | static unsigned long last_interrupt0_time = 0; //Interrupt Debouncing 188 | unsigned long interrupt0_time = millis(); //Interrupt Debouncing 189 | 190 | if (interrupt0_time - last_interrupt0_time > 200) { //Interrupt Debouncing 191 | if (faderChannel < 8) { 192 | faderChannel++; 193 | 194 | Serial.write(0x90); 195 | Serial.write(0x17 + faderChannel); 196 | Serial.write(0x7f); //Note On 197 | Serial.write(0x90); 198 | Serial.write(0x17 + faderChannel); 199 | Serial.write((byte) 0x00); //Note Off 200 | } 201 | } 202 | 203 | last_interrupt0_time = interrupt0_time; //Interrupt Debouncing 204 | } 205 | 206 | //Selects the previous channel in the DAW 207 | void prevChannel() { 208 | static unsigned long last_interrupt1_time = 0; //Interrupt Debouncing 209 | unsigned long interrupt1_time = millis(); //Interrupt Debouncing 210 | 211 | if (interrupt1_time - last_interrupt1_time > 200) { //Interrupt Debouncing 212 | if (faderChannel > 1) { 213 | faderChannel--; 214 | 215 | Serial.write(0x90); 216 | Serial.write(0x17 + faderChannel); 217 | Serial.write(0x7f); //Note On 218 | Serial.write(0x90); 219 | Serial.write(0x17 + faderChannel); 220 | Serial.write((byte) 0x00); //Note Off 221 | } 222 | } 223 | 224 | last_interrupt1_time = interrupt1_time; //Interrupt Debouncing 225 | } 226 | --------------------------------------------------------------------------------