├── Programming └── Pins.png ├── README.md └── NMCode └── NMCode /Programming/Pins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thisisnoiseinc/NMCode/HEAD/Programming/Pins.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NMCode 2 | The Brains That Make Noise Machine (NMSVE) Tick. 3 | 4 | ## Prerequisites 5 | * https://github.com/espressif/arduino-esp32 6 | 7 | ## Programming 8 | 9 | **USB to TTL Converter** 10 | 11 | You'll need a USB to TTL Converter to connect Noise Machine (NMSVE) to your PC. 12 | 13 | See below for reference: 14 | 15 | https://a.co/d/i3A57Qw 16 | 17 | **Pin Diagram** 18 | 19 | ![alt text](https://github.com/thisisnoiseinc/NMCode/blob/main/Programming/Pins.png) 20 | 21 | Top to Bottom (in picture above): 22 | 23 | BOOT 24 |
25 | EN 26 |
27 | GND 28 |
29 | 3V3 30 |
31 | RX 32 |
33 | TX 34 | 35 | To enter BOOT Mode for programming pull "BOOT" to "GND" on startup. 36 | 37 | **Arduino** 38 | 39 | Use "Firebeetle-ESP32" as the board when uploading. 40 | 41 | ## Notes 42 | Originally based off neilbags code: 43 | * https://github.com/neilbags/arduino-esp32-BLE-MIDI 44 | -------------------------------------------------------------------------------- /NMCode/NMCode: -------------------------------------------------------------------------------- 1 | /* 2 | NMCode by this.is.NOISE inc. 3 | 4 | https://github.com/thisisnoiseinc/NMCode 5 | 6 | Built upon: 7 | 8 | "BLE_MIDI Example by neilbags 9 | https://github.com/neilbags/arduino-esp32-BLE-MIDI 10 | 11 | Based on BLE_notify example by Evandro Copercini." 12 | */ 13 | 14 | #include 15 | 16 | #include 17 | 18 | #include 19 | 20 | #include 21 | 22 | #include "esp_bt_main.h" 23 | 24 | #include "esp_bt_device.h" 25 | 26 | #define SERVICE_UUID "03b80e5a-ede8-4b33-a751-6ce34ec4c700" 27 | 28 | #define CHARACTERISTIC_UUID "7772e5db-3868-4112-a1a9-f2669d106bf3" 29 | 30 | 31 | int potPin = 36; // Slider 32 | int rotPin = 39; // Rotary Knob 33 | bool rotMoving = true; 34 | int midiCState = 0; // General current state 35 | int led_Blue = 14; // BLE LED 36 | int led_Green = 4; // CHANNEL LED 37 | const int button = 12; 38 | int potCstate = 0; // Slider current state 39 | int rotCState = 0; // Rotary Knob current state 40 | int outputValue = 0; 41 | int ButtonNote = 0; 42 | int Channel_SelectON = 0; 43 | int Channel_SelectOFF = 0; 44 | int Channel_SelectCC = 0; 45 | int Buttonselect[button] = { // Buttons put in order of reference board. 46 | 16, 47 | 17, 48 | 18, 49 | 21, 50 | 19, 51 | 25, 52 | 22, 53 | 23, 54 | 27, 55 | 26, 56 | 35, 57 | 34 58 | }; 59 | int buttonCstate[button] = {0}; // Button current state 60 | int buttonPState[button] = {0}; // Button previous state 61 | int OffNote[button] = {0}; 62 | int debounceDelay = 5; 63 | int lastDebounceTime[button] = {0}; 64 | int i = 0; 65 | const int numReadings = 15; 66 | int readings[numReadings]; // the readings from the analog input 67 | int readIndex = 0; // the index of the current reading 68 | int total = 0; // the running total 69 | int average1 = 0; // average current state 70 | int lastaverage1 = 0; // average previous state 71 | 72 | BLECharacteristic *pCharacteristic; 73 | 74 | bool deviceConnected = false; 75 | 76 | uint8_t midiPacket[] = { 77 | 78 | 0x80, // header 79 | 80 | 0x80, // timestamp, not implemented 81 | 82 | 0x00, // status 83 | 84 | 0x3c, // 0x3c == 60 == middle c 85 | 86 | 0x00 // velocity 87 | 88 | }; 89 | 90 | class MyServerCallbacks: public BLEServerCallbacks { 91 | 92 | void onConnect(BLEServer* pServer) { 93 | 94 | deviceConnected = true; 95 | 96 | }; 97 | 98 | 99 | 100 | void onDisconnect(BLEServer* pServer) { 101 | 102 | deviceConnected = false; 103 | 104 | } 105 | 106 | }; 107 | 108 | bool initBluetooth() { 109 | 110 | if (!btStart()) { 111 | 112 | Serial.println("Failed to initialize controller"); 113 | return false; 114 | 115 | } 116 | 117 | if (esp_bluedroid_init() != ESP_OK) { 118 | 119 | Serial.println("Failed to initialize bluedroid"); 120 | return false; 121 | 122 | } 123 | 124 | if (esp_bluedroid_enable() != ESP_OK) { 125 | 126 | Serial.println("Failed to enable bluedroid"); 127 | return false; 128 | 129 | } 130 | } 131 | 132 | void setup() { 133 | 134 | Serial.begin(115200); 135 | 136 | initBluetooth(); 137 | const uint8_t* point = esp_bt_dev_get_address(); 138 | 139 | char str[6]; 140 | 141 | sprintf(str, "NMSVE %02X %02X %02X", (int)point[3], (int)point[4], (int)point[5]); 142 | Serial.print(str); 143 | 144 | BLEDevice::init(str); 145 | 146 | BLEServer *pServer = BLEDevice::createServer(); 147 | 148 | pServer->setCallbacks(new MyServerCallbacks()); 149 | 150 | BLEService *pService = pServer->createService(BLEUUID(SERVICE_UUID)); 151 | 152 | pCharacteristic = pService->createCharacteristic( 153 | 154 | BLEUUID(CHARACTERISTIC_UUID), 155 | 156 | BLECharacteristic::PROPERTY_READ | 157 | 158 | BLECharacteristic::PROPERTY_WRITE | 159 | 160 | BLECharacteristic::PROPERTY_NOTIFY | 161 | 162 | BLECharacteristic::PROPERTY_WRITE_NR 163 | 164 | ); 165 | 166 | pCharacteristic->addDescriptor(new BLE2902()); 167 | 168 | pService->start(); 169 | 170 | BLEAdvertising *pAdvertising = pServer->getAdvertising(); 171 | 172 | pAdvertising->addServiceUUID(pService->getUUID()); 173 | 174 | pAdvertising->start(); 175 | 176 | for (int i = 0; i < button; i++) { 177 | 178 | pinMode (Buttonselect[i], INPUT); 179 | pinMode (led_Blue, OUTPUT); 180 | pinMode (led_Green, OUTPUT); 181 | 182 | } 183 | 184 | for (int thisReading = 0; thisReading < numReadings; thisReading++) { 185 | 186 | readings[thisReading] = 0; 187 | 188 | } 189 | 190 | while (Channel_SelectON == 0) { 191 | 192 | digitalWrite(led_Green, HIGH); 193 | 194 | for (int i = 0; i < button; i++) { 195 | 196 | buttonCstate[i] = digitalRead(Buttonselect[i]); 197 | 198 | if (buttonCstate[i] == HIGH) { 199 | 200 | Channel_SelectON = (i + 144); 201 | Channel_SelectOFF = (i + 128); 202 | Channel_SelectCC = (i + 176); 203 | 204 | } 205 | } 206 | } 207 | 208 | digitalWrite(led_Green, LOW); 209 | 210 | } 211 | 212 | void loop(){ 213 | 214 | if (deviceConnected == false) { 215 | 216 | digitalWrite(led_Blue, HIGH); 217 | delay(1000); 218 | digitalWrite(led_Blue, LOW); 219 | delay(1000); 220 | 221 | } 222 | 223 | else { 224 | 225 | digitalWrite(led_Blue, HIGH); 226 | BUTTONS(); 227 | ROTARY(); 228 | 229 | } 230 | } 231 | 232 | void BUTTONS() { 233 | 234 | for (int i = 0; i < button; i++) { 235 | 236 | buttonCstate[i] = digitalRead(Buttonselect[i]); 237 | potCstate = analogRead(potPin); 238 | outputValue = map(potCstate, 0, 4095, 3, 9); 239 | ButtonNote = (outputValue * 12 + i); 240 | 241 | if (outputValue == 3 || outputValue == 5 || outputValue == 7 || outputValue == 9) { 242 | 243 | digitalWrite(led_Green, HIGH); 244 | 245 | } 246 | 247 | else { 248 | 249 | digitalWrite(led_Green, LOW); 250 | 251 | } 252 | 253 | if ((millis() - lastDebounceTime[i]) > debounceDelay) { 254 | 255 | if (buttonPState[i] != buttonCstate[i]) { 256 | 257 | lastDebounceTime[i] = millis(); 258 | 259 | if (buttonCstate[i] == HIGH) { 260 | 261 | midiPacket[2] = Channel_SelectON; 262 | Serial.println(Channel_SelectON); 263 | midiPacket[3] = ButtonNote; 264 | Serial.println(midiPacket[3]); 265 | midiPacket[4] = 100; 266 | pCharacteristic->setValue(midiPacket, 5); 267 | pCharacteristic->notify(); 268 | OffNote[i] = ButtonNote; 269 | 270 | } 271 | 272 | else { 273 | 274 | midiPacket[2] = Channel_SelectOFF; 275 | Serial.println(Channel_SelectOFF); 276 | midiPacket[3] = OffNote[i]; 277 | midiPacket[4] = 0; 278 | pCharacteristic->setValue(midiPacket, 5); 279 | pCharacteristic->notify(); 280 | 281 | } 282 | 283 | buttonPState[i] = buttonCstate[i]; 284 | 285 | } 286 | } 287 | } 288 | } 289 | 290 | void potaverage1() { 291 | 292 | for (int p = 0; p < 15; p++) { 293 | 294 | rotCState = analogRead(rotPin); 295 | midiCState = map(rotCState, 0, 4095, 0, 127); 296 | 297 | total = total - readings[readIndex]; 298 | readings[readIndex] = midiCState; 299 | total = total + readings[readIndex]; 300 | readIndex = readIndex + 1; 301 | 302 | if (readIndex >= numReadings) { 303 | 304 | readIndex = 0; 305 | 306 | } 307 | 308 | average1 = total / numReadings; 309 | delay(1); 310 | 311 | } 312 | } 313 | 314 | void ROTARY(){ 315 | 316 | potaverage1(); 317 | 318 | if (average1 != lastaverage1) { 319 | 320 | rotMoving = true; 321 | 322 | } 323 | 324 | else { 325 | 326 | rotMoving = false; 327 | 328 | } 329 | 330 | if (rotMoving == true) { 331 | 332 | midiPacket[2] = Channel_SelectCC; 333 | Serial.println(Channel_SelectCC); 334 | 335 | midiPacket[3] = 0x01; 336 | Serial.println(0x01); 337 | 338 | midiPacket[4] = average1; 339 | Serial.println(average1); 340 | 341 | pCharacteristic->setValue(midiPacket, 5); 342 | 343 | pCharacteristic->notify(); 344 | 345 | lastaverage1 = average1; 346 | 347 | } 348 | } 349 | --------------------------------------------------------------------------------