├── Calibration └── Calibration.ino ├── README.md ├── bananas └── bananas.ino ├── bassMidi ├── LinkedList.h └── bassMidi.ino ├── capJelly └── capJelly.ino ├── ccMsbLsb └── ccMsbLsb.ino ├── drumServo └── drumServo.ino ├── dueMidi2CvWithLooper └── dueMidi2CvWithLooper.ino ├── floppy └── floppy.ino ├── keyMiduino └── keyMiduino.ino ├── midi2cv_recorder └── midi2cv_recorder.ino ├── midiBLE └── midiBLE.ino ├── midiblue └── midiblue.ino ├── pro53 └── pro53.ino ├── windController ├── AutoRange.cpp ├── AutoRange.h └── windController.ino ├── ym2612 ├── LinkedList.h ├── YM2612.cpp ├── YM2612.h └── ym2612.ino └── ym2612_vgi ├── .DS_Store ├── ._.DS_Store ├── LinkedList.h ├── VGI.h ├── YM2612.cpp ├── YM2612.h └── ym2612.ino /Calibration/Calibration.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | // These constants won't change: 4 | const int sensorPin = A0; // pin that the sensor is attached to 5 | const int ledPin = 9; // pin that the LED is attached to 6 | 7 | // variables: 8 | int sensorValue = 0; // the sensor value 9 | int sensorMin = 1023; // minimum sensor value 10 | int sensorMax = 0; // maximum sensor value 11 | int noiseVal = 30; //dont read below this value 12 | 13 | 14 | void setup() { 15 | // turn on LED to signal the start of the calibration period: 16 | pinMode(13, OUTPUT); 17 | digitalWrite(13, HIGH); 18 | 19 | Serial.begin(9600); 20 | 21 | // calibrate during the first five seconds 22 | while (millis() < 10000) { 23 | sensorValue = analogRead(sensorPin); 24 | 25 | 26 | if (sensorValue > noiseVal) { 27 | 28 | // record the maximum sensor value 29 | if (sensorValue > sensorMax) { 30 | sensorMax = sensorValue; 31 | } 32 | 33 | // record the minimum sensor value 34 | if (sensorValue < sensorMin) { 35 | sensorMin = sensorValue; 36 | } 37 | 38 | 39 | Serial.print("min: "); 40 | Serial.print( sensorMin ); 41 | Serial.print( " max: " ); 42 | Serial.println(sensorMax); 43 | } 44 | delay(1); 45 | 46 | } 47 | 48 | 49 | 50 | 51 | 52 | 53 | // signal the end of the calibration period 54 | digitalWrite(13, LOW); 55 | } 56 | 57 | void loop() { 58 | // read the sensor: 59 | sensorValue = analogRead(sensorPin); 60 | 61 | 62 | if (sensorValue > noiseVal) { 63 | 64 | 65 | // apply the calibration to the sensor reading 66 | sensorValue = map(sensorValue, sensorMin, sensorMax, 0, 255); 67 | 68 | // in case the sensor value is outside the range seen during calibration 69 | sensorValue = constrain(sensorValue, 0, 255); 70 | 71 | Serial.println("val: " + sensorValue); 72 | } 73 | delay(1); 74 | } 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # arduinoProjects 2 | -------------------------------------------------------------------------------- /bananas/bananas.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 4 | -hmNh: 5 | hmyoh 6 | :h-:s: 7 | s:-:y- 8 | .s.:/oo. 9 | -s.-:::s- 10 | o:..+---y 11 | y..-/---h 12 | -o../----h 13 | -s-.::--:/s 14 | `/+-.-:---:h. 15 | ./+-..::----s/ 16 | .:/:.`..:-----s/ 17 | ``..-----:::-.```.------/s: 18 | sy+///::-..```````..-------:oo. 19 | om/::-------::::::------:/so- 20 | `:+o/::::::/::::::::/oo+:` 21 | ./++ooooossoo++/-` 22 | 23 | 24 | 25 | 26 | 27 | Resistor Choice 28 | 29 | Here are some guidelines for resistors but be sure to experiment for a desired response. 30 | 31 | Use a 1 megohm resistor (or less maybe) for absolute touch to activate. 32 | With a 10 megohm resistor the sensor will start to respond 4-6 inches away. 33 | With a 40 megohm resistor the sensor will start to respond 12-24 inches away (dependent on the foil size). Common resistor sizes usually end at 10 megohm so you may have to solder four 10 megohm resistors end to end. 34 | One tradeoff with larger resistors is that the sensor's increased sensitivity means that it is slower. Also if the sensor is exposed metal, it is possible that the send pin will never be able to force a change in the receive (sensor) pin, and the sensor will timeout. 35 | Also experiment with small capacitors (100 pF - .01 uF) to ground, on the sense pin. They improve stability of the sensor. 36 | 37 | */ 38 | 39 | #include 40 | 41 | CapacitiveSensor cs[] = { 42 | CapacitiveSensor(7,2), 43 | CapacitiveSensor(7,3), 44 | CapacitiveSensor(7,4), 45 | CapacitiveSensor(7,5), 46 | CapacitiveSensor(7,6), 47 | }; 48 | 49 | const int UMBRAL = 1000; 50 | int estadoPines[] = {0,0,0,0,0}; 51 | int antirebotes[] = {0,0,0,0,0}; 52 | long maximos[] = {0,0,0,0,0}; 53 | 54 | int notas[] = {60,62,65,67,69}; 55 | int lastValue; 56 | 57 | void setup() 58 | { 59 | Serial.begin(9600); 60 | } 61 | 62 | void cambiarEstadoPin(int pin, int nuevoEstado) { 63 | estadoPines[pin] = nuevoEstado; 64 | antirebotes[pin] = 0; 65 | if(estadoPines[pin] == 1){ 66 | noteOn(notas[pin], 100); 67 | }else{ 68 | noteOff(notas[pin]); 69 | } 70 | 71 | } 72 | 73 | 74 | void loop() 75 | { 76 | for(int i=0;i<5;i++){ 77 | 78 | long total = cs[i].capacitiveSensor(15); 79 | if(total > maximos[i]) 80 | maximos[i] = total; 81 | 82 | int umbral = maximos[i]/10; 83 | byte nuevoEstadoPin = (total > umbral); 84 | 85 | if (estadoPines[i] != nuevoEstadoPin ){ 86 | antirebotes[i] = antirebotes[i] + 1; 87 | 88 | if(antirebotes[i] > 2 ){ 89 | cambiarEstadoPin(i,nuevoEstadoPin); 90 | /* 91 | Serial.print(i); 92 | Serial.print(":"); 93 | Serial.print(total); 94 | Serial.println(" ;"); 95 | */ 96 | } 97 | }else{ 98 | antirebotes[i]= 0; 99 | } 100 | } 101 | } 102 | 103 | 104 | 105 | 106 | // plays a MIDI note. 107 | void noteOn(int pitch, int velocity) { 108 | //return; 109 | Serial.write(0x90); 110 | Serial.write(pitch); 111 | Serial.write(velocity); 112 | } 113 | 114 | void noteOff(int pitch) { 115 | noteOn(pitch, 0); 116 | } 117 | -------------------------------------------------------------------------------- /bassMidi/LinkedList.h: -------------------------------------------------------------------------------- 1 | /* 2 | LinkedList.h - V1.1 - Generic LinkedList implementation 3 | Works better with FIFO, because LIFO will need to 4 | search the entire List to find the last one; 5 | 6 | For instructions, go to https://github.com/ivanseidel/LinkedList 7 | 8 | Created by Ivan Seidel Gomes, March, 2013. 9 | Released into the public domain. 10 | */ 11 | 12 | 13 | #ifndef LinkedList_h 14 | #define LinkedList_h 15 | 16 | template 17 | struct ListNode 18 | { 19 | T data; 20 | ListNode *next; 21 | }; 22 | 23 | template 24 | class LinkedList{ 25 | 26 | protected: 27 | int _size; 28 | ListNode *root; 29 | ListNode *last; 30 | 31 | // Helps "get" method, by saving last position 32 | ListNode *lastNodeGot; 33 | int lastIndexGot; 34 | // isCached should be set to FALSE 35 | // everytime the list suffer changes 36 | bool isCached; 37 | 38 | ListNode* getNode(int index); 39 | 40 | public: 41 | LinkedList(); 42 | ~LinkedList(); 43 | 44 | /* 45 | Returns current size of LinkedList 46 | */ 47 | virtual int size(); 48 | /* 49 | Adds a T object in the specified index; 50 | Unlink and link the LinkedList correcly; 51 | Increment _size 52 | */ 53 | virtual bool add(int index, T); 54 | /* 55 | Adds a T object in the end of the LinkedList; 56 | Increment _size; 57 | */ 58 | virtual bool add(T); 59 | /* 60 | Adds a T object in the start of the LinkedList; 61 | Increment _size; 62 | */ 63 | virtual bool unshift(T); 64 | /* 65 | Set the object at index, with T; 66 | Increment _size; 67 | */ 68 | virtual bool set(int index, T); 69 | /* 70 | Remove object at index; 71 | If index is not reachable, returns false; 72 | else, decrement _size 73 | */ 74 | virtual T remove(int index); 75 | /* 76 | Remove last object; 77 | */ 78 | virtual T pop(); 79 | /* 80 | Remove first object; 81 | */ 82 | virtual T shift(); 83 | /* 84 | Get the index'th element on the list; 85 | Return Element if accessible, 86 | else, return false; 87 | */ 88 | virtual T get(int index); 89 | 90 | /* 91 | Clear the entire array 92 | */ 93 | virtual void clear(); 94 | 95 | }; 96 | 97 | // Initialize LinkedList with false values 98 | template 99 | LinkedList::LinkedList() 100 | { 101 | root=NULL; 102 | last=NULL; 103 | _size=0; 104 | 105 | lastNodeGot = root; 106 | lastIndexGot = 0; 107 | isCached = false; 108 | } 109 | 110 | // Clear Nodes and free Memory 111 | template 112 | LinkedList::~LinkedList() 113 | { 114 | ListNode* tmp; 115 | while(root!=false) 116 | { 117 | tmp=root; 118 | root=root->next; 119 | delete tmp; 120 | } 121 | last = NULL; 122 | _size=0; 123 | isCached = false; 124 | } 125 | 126 | /* 127 | Actualy "logic" coding 128 | */ 129 | 130 | template 131 | ListNode* LinkedList::getNode(int index){ 132 | 133 | int _pos = 0; 134 | ListNode* current = root; 135 | 136 | // Check if the node trying to get is 137 | // immediatly AFTER the previous got one 138 | if(isCached && lastIndexGot <= index){ 139 | _pos = lastIndexGot; 140 | current = lastNodeGot; 141 | } 142 | 143 | while(_pos < index && current){ 144 | current = current->next; 145 | 146 | _pos++; 147 | } 148 | 149 | // Check if the object index got is the same as the required 150 | if(_pos == index){ 151 | isCached = true; 152 | lastIndexGot = index; 153 | lastNodeGot = current; 154 | 155 | return current; 156 | } 157 | 158 | return false; 159 | } 160 | 161 | template 162 | int LinkedList::size(){ 163 | return _size; 164 | } 165 | 166 | template 167 | bool LinkedList::add(int index, T _t){ 168 | 169 | if(index >= _size) 170 | return add(_t); 171 | 172 | if(index == 0) 173 | return unshift(_t); 174 | 175 | ListNode *tmp = new ListNode(), 176 | *_prev = getNode(index-1); 177 | tmp->data = _t; 178 | tmp->next = _prev->next; 179 | _prev->next = tmp; 180 | 181 | _size++; 182 | isCached = false; 183 | 184 | return true; 185 | } 186 | 187 | template 188 | bool LinkedList::add(T _t){ 189 | 190 | ListNode *tmp = new ListNode(); 191 | tmp->data = _t; 192 | tmp->next = NULL; 193 | 194 | if(root){ 195 | // Already have elements inserted 196 | last->next = tmp; 197 | last = tmp; 198 | }else{ 199 | // First element being inserted 200 | root = tmp; 201 | last = tmp; 202 | } 203 | 204 | _size++; 205 | isCached = false; 206 | 207 | return true; 208 | } 209 | 210 | template 211 | bool LinkedList::unshift(T _t){ 212 | 213 | if(_size == 0) 214 | return add(_t); 215 | 216 | ListNode *tmp = new ListNode(); 217 | tmp->next = root; 218 | tmp->data = _t; 219 | root = tmp; 220 | 221 | _size++; 222 | isCached = false; 223 | 224 | return true; 225 | } 226 | 227 | template 228 | bool LinkedList::set(int index, T _t){ 229 | // Check if index position is in bounds 230 | if(index < 0 || index >= _size) 231 | return false; 232 | 233 | getNode(index)->data = _t; 234 | return true; 235 | } 236 | 237 | template 238 | T LinkedList::pop(){ 239 | if(_size <= 0) 240 | return T(); 241 | 242 | isCached = false; 243 | 244 | if(_size >= 2){ 245 | ListNode *tmp = getNode(_size - 2); 246 | T ret = tmp->next->data; 247 | delete(tmp->next); 248 | tmp->next = NULL; 249 | last = tmp; 250 | _size--; 251 | return ret; 252 | }else{ 253 | // Only one element left on the list 254 | T ret = root->data; 255 | delete(root); 256 | root = NULL; 257 | last = NULL; 258 | _size = 0; 259 | return ret; 260 | } 261 | } 262 | 263 | template 264 | T LinkedList::shift(){ 265 | if(_size <= 0) 266 | return T(); 267 | 268 | if(_size > 1){ 269 | ListNode *_next = root->next; 270 | T ret = root->data; 271 | delete(root); 272 | root = _next; 273 | _size --; 274 | isCached = false; 275 | 276 | return ret; 277 | }else{ 278 | // Only one left, then pop() 279 | return pop(); 280 | } 281 | 282 | } 283 | 284 | template 285 | T LinkedList::remove(int index){ 286 | if (index < 0 || index >= _size) 287 | { 288 | return T(); 289 | } 290 | 291 | if(index == 0) 292 | return shift(); 293 | 294 | if (index == _size-1) 295 | { 296 | return pop(); 297 | } 298 | 299 | ListNode *tmp = getNode(index - 1); 300 | ListNode *toDelete = tmp->next; 301 | T ret = toDelete->data; 302 | tmp->next = tmp->next->next; 303 | delete(toDelete); 304 | _size--; 305 | isCached = false; 306 | return ret; 307 | } 308 | 309 | 310 | template 311 | T LinkedList::get(int index){ 312 | ListNode *tmp = getNode(index); 313 | 314 | return (tmp ? tmp->data : T()); 315 | } 316 | 317 | template 318 | void LinkedList::clear(){ 319 | while(size() > 0) 320 | shift(); 321 | } 322 | 323 | #endif 324 | -------------------------------------------------------------------------------- /bassMidi/bassMidi.ino: -------------------------------------------------------------------------------- 1 | // Auduino, the Lo-Fi granular synthesiser 2 | // Help: http://code.google.com/p/tinkerit/wiki/Auduino 3 | // More help: http://groups.google.com/group/auduino 4 | 5 | // Analog in 0: Grain 1 pitch 6 | // Analog in 1: Grain 2 decay 7 | // Analog in 2: Grain 1 decay 8 | // Analog in 3: Grain 2 pitch 9 | // Digital 3: Audio out (Digital 11 on ATmega8) 10 | 11 | #include 12 | #include 13 | #include 14 | #include "LinkedList.h" 15 | 16 | 17 | bool drumTriggered=false; 18 | long drumTriggeredAt; 19 | long pulseDuration=20; 20 | 21 | struct CustomMidiSettings : public midi::DefaultSettings { 22 | static const unsigned BaudRate = 9600; 23 | }; 24 | MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial, MIDI, CustomMidiSettings); 25 | 26 | uint16_t syncPhaseAcc; 27 | uint16_t syncPhaseInc; 28 | uint16_t grainPhaseAcc; 29 | uint16_t grainPhaseInc; 30 | uint16_t grainAmp; 31 | uint8_t grainDecay; 32 | uint16_t grain2PhaseAcc; 33 | uint16_t grain2PhaseInc; 34 | uint16_t grain2Amp; 35 | uint8_t grain2Decay; 36 | uint8_t grainPhaseIncMidiCC; 37 | uint8_t grainDecayMidiCC; 38 | uint8_t grain2PhaseIncMidiCC; 39 | uint8_t grain2DecayMidiCC; 40 | 41 | LinkedList notes_stack = LinkedList(); 42 | 43 | 44 | #define GRAIN_FREQ_CONTROL (1) 45 | #define GRAIN_DECAY_CONTROL (2) 46 | #define GRAIN2_FREQ_CONTROL (3) 47 | #define GRAIN2_DECAY_CONTROL (4) 48 | 49 | 50 | #define PULSE_PIN 4 51 | 52 | #define PWM_PIN 3 53 | #define PWM_VALUE OCR2B 54 | #define PWM_INTERRUPT TIMER2_OVF_vect 55 | 56 | // Smooth logarithmic mapping 57 | // 58 | uint16_t antilogTable[] = { 59 | 64830,64132,63441,62757,62081,61413,60751,60097,59449,58809,58176,57549,56929,56316,55709,55109, 60 | 54515,53928,53347,52773,52204,51642,51085,50535,49991,49452,48920,48393,47871,47356,46846,46341, 61 | 45842,45348,44859,44376,43898,43425,42958,42495,42037,41584,41136,40693,40255,39821,39392,38968, 62 | 38548,38133,37722,37316,36914,36516,36123,35734,35349,34968,34591,34219,33850,33486,33125,32768 63 | }; 64 | uint16_t mapPhaseInc(uint16_t input) { 65 | return (antilogTable[input & 0x3f]) >> (input >> 6); 66 | } 67 | 68 | // Stepped chromatic mapping 69 | // 70 | uint16_t midiTable[] = { 71 | 17,18,19,20,22,23,24,26,27,29,31,32,34,36,38,41,43,46,48,51,54,58,61,65,69,73, 72 | 77,82,86,92,97,103,109,115,122,129,137,145,154,163,173,183,194,206,218,231, 73 | 244,259,274,291,308,326,346,366,388,411,435,461,489,518,549,581,616,652,691, 74 | 732,776,822,871,923,978,1036,1097,1163,1232,1305,1383,1465,1552,1644,1742, 75 | 1845,1955,2071,2195,2325,2463,2610,2765,2930,3104,3288,3484,3691,3910,4143, 76 | 4389,4650,4927,5220,5530,5859,6207,6577,6968,7382,7821,8286,8779,9301,9854, 77 | 10440,11060,11718,12415,13153,13935,14764,15642,16572,17557,18601,19708,20879, 78 | 22121,23436,24830,26306 79 | }; 80 | uint16_t mapMidi(uint16_t input) { 81 | return (midiTable[(1023-input) >> 3]); 82 | } 83 | 84 | // Stepped Pentatonic mapping 85 | // 86 | uint16_t pentatonicTable[54] = { 87 | 0,19,22,26,29,32,38,43,51,58,65,77,86,103,115,129,154,173,206,231,259,308,346, 88 | 411,461,518,616,691,822,923,1036,1232,1383,1644,1845,2071,2463,2765,3288, 89 | 3691,4143,4927,5530,6577,7382,8286,9854,11060,13153,14764,16572,19708,22121,26306 90 | }; 91 | 92 | uint16_t mapPentatonic(uint16_t input) { 93 | uint8_t value = (1023-input) / (1024/53); 94 | return (pentatonicTable[value]); 95 | } 96 | 97 | void audioOn() { 98 | // Set up PWM to 31.25kHz, phase accurate 99 | TCCR2A = _BV(COM2B1) | _BV(WGM20); 100 | TCCR2B = _BV(CS20); 101 | TIMSK2 = _BV(TOIE2); 102 | } 103 | 104 | void handleNoteOn(byte channel, byte pitch, byte velocity) { 105 | if(channel==10){ 106 | digitalWrite(PULSE_PIN, 1); 107 | drumTriggered = true; 108 | drumTriggeredAt = millis(); 109 | return; 110 | } 111 | 112 | 113 | // remove note from the stack if already there 114 | for(int n = 0;n0){ 131 | // if pitch corresponds to last note in the stack 132 | // set syncPhaseInc to previous note (if exists) 133 | if( pitch == notes_stack.get(notes_stack.size()-1)){ 134 | notes_stack.pop(); 135 | if(notes_stack.size()>0){ 136 | uint8_t previous = notes_stack.get(notes_stack.size()-1); 137 | syncPhaseInc = midiTable[previous]; 138 | } 139 | } 140 | } 141 | 142 | // remove notes from the stack 143 | for(int n = 0;n500){ 174 | if(syncPhaseInc >0){ 175 | syncPhaseInc =0; 176 | }else{ 177 | syncPhaseInc = midiTable[notas[index]]; 178 | index++; 179 | index %=7; 180 | 181 | } 182 | lastMillis = curMillis; 183 | } 184 | 185 | 186 | grainPhaseInc = mapPhaseInc(analogRead(GRAIN_FREQ_CONTROL)) / 2; 187 | grainDecay = analogRead(GRAIN_DECAY_CONTROL) / 8; 188 | grain2PhaseInc = mapPhaseInc(analogRead(GRAIN2_FREQ_CONTROL)) / 2; 189 | grain2Decay = analogRead(GRAIN2_DECAY_CONTROL) / 4; 190 | 191 | 192 | 193 | } 194 | 195 | SIGNAL(PWM_INTERRUPT) 196 | { 197 | uint8_t value; 198 | uint16_t output; 199 | 200 | syncPhaseAcc += syncPhaseInc; 201 | if (syncPhaseAcc < syncPhaseInc) { 202 | // Time to start the next grain 203 | grainPhaseAcc = 0; 204 | grainAmp = 0x7fff; 205 | grain2PhaseAcc = 0; 206 | grain2Amp = 0x7fff; 207 | } 208 | 209 | // Increment the phase of the grain oscillators 210 | grainPhaseAcc += grainPhaseInc; 211 | grain2PhaseAcc += grain2PhaseInc; 212 | 213 | // Convert phase into a triangle wave 214 | value = (grainPhaseAcc >> 7) & 0xff; 215 | if (grainPhaseAcc & 0x8000) value = ~value; 216 | // Multiply by current grain amplitude to get sample 217 | output = value * (grainAmp >> 8); 218 | 219 | // Repeat for second grain 220 | value = (grain2PhaseAcc >> 7) & 0xff; 221 | if (grain2PhaseAcc & 0x8000) value = ~value; 222 | output += value * (grain2Amp >> 8); 223 | 224 | // Make the grain amplitudes decay by a factor every sample (exponential decay) 225 | grainAmp -= (grainAmp >> 8) * grainDecay; 226 | grain2Amp -= (grain2Amp >> 8) * grain2Decay; 227 | 228 | // Scale output to the available range, clipping if necessary 229 | output >>= 9; 230 | if (output > 255) output = 255; 231 | 232 | // Output to PWM (this is faster than using analogWrite) 233 | PWM_VALUE = output; 234 | } 235 | -------------------------------------------------------------------------------- /capJelly/capJelly.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | CapacitiveSensor cs_4_2 = CapacitiveSensor(4,2); // 10M resistor between pins 4 & 2, pin 2 is sensor pin, add a wire and or foil if desired 4 | 5 | void setup() 6 | { 7 | Serial.begin(9600); 8 | } 9 | 10 | void loop() 11 | { 12 | 13 | long total1 = cs_4_2.capacitiveSensor(50); 14 | byte m = map(total1, 1, 1 000, 0, 127); 15 | cc(m); 16 | delay(1); // arbitrary delay to limit data to serial port 17 | } 18 | 19 | 20 | void cc(byte val) { 21 | Serial.write(0xB0); 22 | Serial.write(0x10); 23 | Serial.write(( (byte)val) & 0x3F); 24 | } 25 | 26 | 27 | // plays a MIDI note. 28 | void bend(unsigned int val) { 29 | Serial.write(0xE0); 30 | //Serial.write(0x00); 31 | //Serial.write(0x40); 32 | Serial.write(( (byte)val) & 0x3F); //lsb 33 | Serial.write( ((byte)(val>>7)) & 0x3F); //msb 34 | } 35 | 36 | 37 | -------------------------------------------------------------------------------- /ccMsbLsb/ccMsbLsb.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | const int numReadings = 250; 4 | 5 | int readings[numReadings]; // the readings from the analog input 6 | int readIndex = 0; // the index of the current reading 7 | int total = 0; // the running total 8 | int average = 0; // the average 9 | int inputPin = A0; 10 | 11 | void setup() { 12 | Serial.begin(9600); 13 | 14 | // initialize all the readings to 0: 15 | for (int thisReading = 0; thisReading < numReadings; thisReading++) { 16 | readings[thisReading] = 0; 17 | } 18 | 19 | } 20 | 21 | void loop() { 22 | 23 | 24 | // subtract the last reading: 25 | total = total - readings[readIndex]; 26 | // read from the sensor: 27 | readings[readIndex] = analogRead(inputPin); 28 | // add the reading to the total: 29 | total = total + readings[readIndex]; 30 | // advance to the next position in the array: 31 | readIndex = readIndex + 1; 32 | 33 | // if we're at the end of the array... 34 | if (readIndex >= numReadings) { 35 | // ...wrap around to the beginning: 36 | readIndex = 0; 37 | } 38 | 39 | // calculate the average: 40 | average = total / numReadings; 41 | 42 | unsigned int a = average; 43 | 44 | byte msb = (a >> 7) & B01111111; 45 | byte lsb = a & B01111111; 46 | 47 | //SendMidiCC( 2, msb); 48 | SendMidiCC( 25, lsb); 49 | 50 | 51 | 52 | delay(1); // delay in between reads for stability 53 | 54 | } 55 | 56 | void SendMidiCC(byte byte2, byte byte3){ 57 | Serial.write(0xB0); 58 | Serial.write(byte2); 59 | Serial.write(byte3); 60 | } 61 | 62 | -------------------------------------------------------------------------------- /drumServo/drumServo.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | struct BleSettings : public midi::DefaultSettings 4 | { 5 | static const long BaudRate = 9600; 6 | }; 7 | 8 | MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial, midiB, BleSettings); 9 | 10 | Servo servo0; 11 | Servo servo1; 12 | 13 | 14 | void handleNoteOn(byte channel, byte pitch, byte velocity) 15 | { 16 | if(pitch=60) 17 | servo0.write(55); 18 | //else 19 | // servo1.write(20); 20 | } 21 | 22 | void handleNoteOff(byte channel, byte pitch, byte velocity) 23 | { 24 | if(pitch=60) 25 | servo0.write(35); 26 | //else 27 | // servo1.write(0); 28 | } 29 | 30 | void setup() { 31 | servo0.attach(11); 32 | servo1.attach(9); 33 | delay(500); 34 | servo0.write(0); 35 | servo1.write(0); 36 | delay(500); 37 | servo0.write(20); 38 | servo1.write(20); 39 | midiB.setHandleNoteOn(handleNoteOn); // Put only the name of the function 40 | midiB.setHandleNoteOff(handleNoteOff); 41 | midiB.begin(MIDI_CHANNEL_OMNI); 42 | 43 | } 44 | 45 | void loop() { 46 | // Call MIDI.read the fastest you can for real-time performance. 47 | midiB.read(); 48 | } 49 | 50 | -------------------------------------------------------------------------------- /dueMidi2CvWithLooper/dueMidi2CvWithLooper.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct SeqNote{ 4 | byte note; 5 | byte velocity; 6 | uint32_t time; 7 | }; 8 | 9 | #define SEQ_COUNT 1000 10 | #define MAX_SEQ_COUNT (UINT32_MAX-1) //in millis 11 | 12 | byte command; 13 | byte note; 14 | byte velocity; 15 | volatile uint32_t freq = 0; 16 | SeqNote seq[SEQ_COUNT]; 17 | volatile uint32_t seq_index = 0; 18 | volatile uint32_t seq_last_index = 0; 19 | volatile uint32_t seq_counter = 0; 20 | volatile uint32_t seq_length = 0; 21 | volatile bool seq_on = false; 22 | volatile bool prepared_to_rec = false; 23 | volatile bool rec_on = false; 24 | 25 | 26 | int myLed = 13; 27 | bool ledOn = false; 28 | 29 | void seqHandler(){ 30 | if(rec_on){ 31 | if(seq_counter>=seq_length){ 32 | Serial.println("rec overload 1"); 33 | 34 | stopRec(); 35 | startSeq(); 36 | } 37 | seq_counter++; 38 | } 39 | 40 | 41 | if(seq_on){ 42 | if(seq_counter>=seq_length){ 43 | seq_counter=0; 44 | seq_index=0; 45 | Serial.println("loop seq"); 46 | return; 47 | } 48 | 49 | if(seq_counter>=seq[seq_index].time){ 50 | changeFreq(seq[seq_index].note); 51 | if(seq_index < seq_last_index) 52 | seq_index++; 53 | } 54 | seq_counter++; 55 | } 56 | 57 | 58 | } 59 | 60 | void changeFreq(int note){ 61 | static int last_note = 0; 62 | 63 | if(note != last_note){ 64 | last_note = note; 65 | Serial.println("change freq"); 66 | int val = map(note, 48, 96, 0, 4095); 67 | analogWrite(DAC0, val); 68 | 69 | } 70 | 71 | } 72 | 73 | 74 | void setup() { 75 | 76 | 77 | analogWriteResolution(12); 78 | Serial.begin(9600); 79 | Serial1.begin(31250); 80 | analogWrite(DAC0, 0); 81 | Serial.println("started"); 82 | 83 | pinMode(myLed, OUTPUT); 84 | Timer3.attachInterrupt(seqHandler); 85 | Timer3.start(1000); // Calls every 1ms 86 | 87 | } 88 | 89 | 90 | void loop () { 91 | 92 | if (Serial1.available()>2){ 93 | 94 | int count = Serial1.available();//read first byte 95 | command = Serial1.read();//read first byte 96 | note = Serial1.read();//read next byte 97 | velocity = Serial1.read();//read final byte 98 | 99 | 100 | // note on message starting 101 | if (command== 144){ 102 | Serial.print(command); 103 | Serial.print(" - "); 104 | Serial.print(note); 105 | Serial.print(" - "); 106 | Serial.print(velocity); 107 | Serial.print(" - "); 108 | Serial.println(count); 109 | 110 | if (note >=48 && note <=96){ 111 | if(prepared_to_rec) 112 | startRec(); 113 | 114 | if(rec_on){ 115 | SeqNote seqn = { note , velocity , seq_counter }; 116 | seq[seq_index] = seqn; 117 | seq_last_index = seq_index; 118 | seq_index++; 119 | 120 | if (seq_index>=SEQ_COUNT){ 121 | Serial.println("rec overload 2"); 122 | stopRec(); 123 | startSeq(); 124 | } 125 | } 126 | 127 | changeFreq(note); 128 | } 129 | } 130 | 131 | // note off message starting starting 132 | if (command== 128){ 133 | } 134 | 135 | 136 | //transport 137 | if (command== 176){ 138 | //rec button 139 | if (note== 117 && velocity>0){ 140 | prepared_to_rec= true; 141 | } 142 | //play button 143 | if (note== 115 && velocity>0){ 144 | if(prepared_to_rec) 145 | startRec(); 146 | else 147 | startSeq(); 148 | } 149 | //stop button 150 | if (note== 114 && velocity>0){ 151 | if(seq_on){ 152 | stopSeq(); 153 | } 154 | if(rec_on){ 155 | stopRec(); 156 | } 157 | } 158 | } 159 | 160 | 161 | 162 | } 163 | 164 | 165 | } 166 | 167 | 168 | void startRec(){ 169 | Serial.println("start recording"); 170 | seq_length = MAX_SEQ_COUNT; 171 | rec_on = true; 172 | seq_counter = 0; 173 | seq_index = 0; 174 | prepared_to_rec= false; 175 | 176 | } 177 | 178 | void stopRec(){ 179 | Serial.println("stop recording"); 180 | seq_length = seq_counter; 181 | rec_on = false; 182 | seq_counter=0; 183 | seq_index=0; 184 | prepared_to_rec= false; 185 | } 186 | 187 | void startSeq(){ 188 | Serial.println("start seq"); 189 | seq_on = true; 190 | seq_counter=0; 191 | seq_index=0; 192 | } 193 | 194 | 195 | void stopSeq(){ 196 | Serial.println("stop seq"); 197 | seq_on = false; 198 | prepared_to_rec= false; 199 | } 200 | 201 | -------------------------------------------------------------------------------- /floppy/floppy.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct MidiSettings : public midi::DefaultSettings 4 | { 5 | static const long BaudRate = 9600; 6 | }; 7 | 8 | MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial, MIDI, MidiSettings); 9 | 10 | #include 11 | 12 | #define RESOLUTION 40 //Microsecond resolution for notes 13 | byte MAX_POSITION = 158; 14 | 15 | byte currentPosition = 0; 16 | int currentState = LOW; 17 | int currentStateDir = LOW; 18 | unsigned int currentPeriod = 0; 19 | unsigned int currentTick = 0; 20 | byte keys[128]= {0}; 21 | 22 | 23 | unsigned int microPeriods[] = { 24 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26 | 30578, 28861, 27242, 25713, 24270, 22909, 21622, 20409, 19263, 18182, 17161, 16198, //C1 - B1 27 | 15289, 14436, 13621, 12856, 12135, 11454, 10811, 10205, 9632, 9091, 8581, 8099, //C2 - B2 28 | 7645, 7218, 6811, 6428, 6068, 5727, 5406, 5103, 4816, 4546, 4291, 4050, //C3 - B3 29 | 3823, 3609, 3406, 3214, 3034, 2864, 2703, 2552, 2408, 2273, 2146, 2025, //C4 - B4 30 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 33 | }; 34 | 35 | 36 | void handleNoteOn(byte channel, byte pitch, byte velocity) 37 | { 38 | currentPeriod = microPeriods[pitch] / (RESOLUTION * 2); 39 | keys[pitch] = 1; 40 | } 41 | 42 | void handleNoteOff(byte channel, byte pitch, byte velocity) 43 | { 44 | keys[pitch] = 0; 45 | for(int i=0;i<128;i++){ 46 | //quit if key is still on 47 | if(keys[i]>0) 48 | return; 49 | } 50 | currentPeriod = 0; 51 | 52 | } 53 | 54 | void setup(){ 55 | pinMode(2, OUTPUT); // Step control 1 56 | pinMode(3, OUTPUT); // Direction 1 57 | pinMode(13, OUTPUT); 58 | 59 | 60 | resetAll(); 61 | delay(2000); 62 | 63 | Timer1.initialize(RESOLUTION); // Set up a timer at the defined resolution 64 | Timer1.attachInterrupt(tick); // Attach the tick function 65 | 66 | MIDI.setHandleNoteOn(handleNoteOn); // Put only the name of the function 67 | MIDI.setHandleNoteOff(handleNoteOff); 68 | MIDI.begin(MIDI_CHANNEL_OMNI); 69 | 70 | } 71 | 72 | long prevMillis = 0; 73 | int note = 25; 74 | 75 | void loop(){ 76 | MIDI.read(); 77 | 78 | long currMillis = millis(); 79 | if (currMillis -prevMillis > 300){ 80 | 81 | //currentPeriod = microPeriods[note] / (RESOLUTION * 2); 82 | 83 | note++; 84 | if(note > 24+4*12) 85 | note = 24; 86 | 87 | prevMillis = currMillis; 88 | } 89 | } 90 | 91 | void tick() 92 | { 93 | if (currentPeriod>0){ 94 | currentTick++; 95 | if (currentTick >= currentPeriod){ 96 | togglePin(); 97 | currentTick=0; 98 | } 99 | } 100 | 101 | } 102 | 103 | void togglePin() { 104 | 105 | //Switch directions if end has been reached 106 | if (currentPosition >= MAX_POSITION) { 107 | currentStateDir = HIGH; 108 | digitalWrite(3,HIGH); 109 | } 110 | else if (currentPosition <= 0) { 111 | currentStateDir = LOW; 112 | digitalWrite(3,LOW); 113 | } 114 | 115 | //Update currentPosition 116 | if (currentStateDir == HIGH){ 117 | currentPosition--; 118 | } 119 | else { 120 | currentPosition++; 121 | } 122 | 123 | //Pulse the control pin 124 | digitalWrite(2,currentState); 125 | currentState = !currentState; 126 | } 127 | 128 | 129 | void resetAll(){ 130 | 131 | digitalWrite(3,HIGH); // Go in reverse 132 | for (byte s=0;s<250;s++){ // For max drive's position 133 | digitalWrite(2,HIGH); 134 | digitalWrite(2,LOW); 135 | delay(5); 136 | } 137 | 138 | currentPosition = 0; 139 | digitalWrite(3,LOW); 140 | currentState = 0; 141 | currentStateDir = LOW; 142 | 143 | } 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /keyMiduino/keyMiduino.ino: -------------------------------------------------------------------------------- 1 | // Analog in 0: Grain 1 pitch 2 | // Analog in 1: Grain 2 decay 3 | // Analog in 2: Grain 1 decay 4 | // Analog in 3: Grain 2 pitch 5 | // Digital 3: Audio out (Digital 11 on ATmega8) 6 | 7 | #include 8 | #include 9 | //#include 10 | #include "LinkedList.h" 11 | #include 12 | 13 | #define KB_DATA_PIN 4 14 | #define KB_IRQ_PIN 2 15 | 16 | PS2KeyAdvanced keyboard; 17 | 18 | //struct CustomMidiSettings : public midi::DefaultSettings { 19 | // static const unsigned BaudRate = 9600; 20 | //}; 21 | //MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial,Serial,MIDI,CustomMidiSettings); 22 | 23 | uint16_t syncPhaseAcc; 24 | uint16_t syncPhaseInc; 25 | uint16_t grainPhaseAcc; 26 | uint16_t grainPhaseInc; 27 | uint16_t grainAmp; 28 | uint8_t grainDecay; 29 | uint16_t grain2PhaseAcc; 30 | uint16_t grain2PhaseInc; 31 | uint16_t grain2Amp; 32 | uint8_t grain2Decay; 33 | 34 | uint8_t grainPhaseIncMidiCC; 35 | uint8_t grainDecayMidiCC; 36 | uint8_t grain2PhaseIncMidiCC; 37 | uint8_t grain2DecayMidiCC; 38 | 39 | LinkedList notes_stack = LinkedList(); 40 | 41 | 42 | #define GRAIN_FREQ_CONTROL (1) 43 | #define GRAIN_DECAY_CONTROL (2) 44 | #define GRAIN2_FREQ_CONTROL (3) 45 | #define GRAIN2_DECAY_CONTROL (4) 46 | 47 | 48 | #define PWM_PIN 3 49 | #define PWM_VALUE OCR2B 50 | #define PWM_INTERRUPT TIMER2_OVF_vect 51 | 52 | // Smooth logarithmic mapping 53 | // 54 | uint16_t antilogTable[] = { 55 | 64830,64132,63441,62757,62081,61413,60751,60097,59449,58809,58176,57549,56929,56316,55709,55109, 56 | 54515,53928,53347,52773,52204,51642,51085,50535,49991,49452,48920,48393,47871,47356,46846,46341, 57 | 45842,45348,44859,44376,43898,43425,42958,42495,42037,41584,41136,40693,40255,39821,39392,38968, 58 | 38548,38133,37722,37316,36914,36516,36123,35734,35349,34968,34591,34219,33850,33486,33125,32768 59 | }; 60 | uint16_t mapPhaseInc(uint16_t input) { 61 | return (antilogTable[input & 0x3f]) >> (input >> 6); 62 | } 63 | 64 | uint16_t midiTable[] = { 65 | 17,18,19,20,22,23,24,26,27,29,31,32,34,36,38,41,43,46,48,51,54,58,61,65,69,73, 66 | 77,82,86,92,97,103,109,115,122,129,137,145,154,163,173,183,194,206,218,231, 67 | 244,259,274,291,308,326,346,366,388,411,435,461,489,518,549,581,616,652,691, 68 | 732,776,822,871,923,978,1036,1097,1163,1232,1305,1383,1465,1552,1644,1742, 69 | 1845,1955,2071,2195,2325,2463,2610,2765,2930,3104,3288,3484,3691,3910,4143, 70 | 4389,4650,4927,5220,5530,5859,6207,6577,6968,7382,7821,8286,8779,9301,9854, 71 | 10440,11060,11718,12415,13153,13935,14764,15642,16572,17557,18601,19708,20879, 72 | 22121,23436,24830,26306 73 | }; 74 | uint16_t mapMidi(uint16_t input) { 75 | return (midiTable[(1023-input) >> 3]); 76 | } 77 | 78 | 79 | uint8_t kb2Midi[] = { 80 | 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,0,0,0,0, 81 | 0,0,0,0,0,0,0,0,63,0,49,51,0,54,56,58,0,61,0,48,0,50,52,0,0,0,43,40,39,52,0,42,44, 82 | 60,46,0,49,47,45,62,64,48,53,37,55,59,41,50,38,57,36,51,0,65,67,66,0,0,0,0,0,0,0,0, 83 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 84 | }; 85 | 86 | void audioOn() { 87 | // Set up PWM to 31.25kHz,phase accurate 88 | TCCR2A = _BV(COM2B1) | _BV(WGM20); 89 | TCCR2B = _BV(CS20); 90 | TIMSK2 = _BV(TOIE2); 91 | } 92 | 93 | 94 | 95 | void readKb(){ 96 | if( keyboard.available() ) { 97 | uint16_t c = keyboard.read(); 98 | if( c > 0 ) { 99 | //Serial.println( c,HEX ); 100 | uint8_t k = c & 0xFF; 101 | uint8_t m = kb2Midi[k]; 102 | uint8_t s = c >> 8; 103 | if(m>0){ 104 | if( s==0){ 105 | handleNoteOn(0,m,100); 106 | }else{ 107 | handleNoteOff(0,m,100); 108 | } 109 | }else{ 110 | //not a note 111 | 112 | if( s==1){ 113 | switch(k) { 114 | case 0x61: 115 | if(grainPhaseIncMidiCC>0) grainPhaseIncMidiCC--; 116 | break; 117 | case 0x62: 118 | if(grainPhaseIncMidiCC<127) grainPhaseIncMidiCC++; 119 | break; 120 | case 0x63: 121 | if(grainDecayMidiCC>0) grainDecayMidiCC--; 122 | break; 123 | case 0x64: 124 | if(grainDecayMidiCC<127) grainDecayMidiCC++; 125 | break; 126 | case 0x65: 127 | if(grain2PhaseIncMidiCC>0) grain2PhaseIncMidiCC--; 128 | break; 129 | case 0x66: 130 | if(grain2PhaseIncMidiCC<127) grain2PhaseIncMidiCC++; 131 | break; 132 | case 0x67: 133 | if(grain2DecayMidiCC>0) grain2DecayMidiCC--; 134 | break; 135 | case 0x68: 136 | if(grain2DecayMidiCC<127) grain2DecayMidiCC++; 137 | break; 138 | } 139 | Serial.println( k,DEC ); 140 | Serial.println( grainPhaseIncMidiCC,DEC ); 141 | 142 | grainPhaseInc = mapPhaseInc(grainPhaseIncMidiCC*8) / 2; 143 | grainDecay = grainDecayMidiCC*2; 144 | grain2PhaseInc = mapPhaseInc(grain2PhaseIncMidiCC*8) / 2; 145 | grain2Decay = grainDecayMidiCC*2; 146 | 147 | } 148 | 149 | 150 | 151 | 152 | } 153 | } 154 | } 155 | } 156 | 157 | 158 | void handleNoteOn(byte channel,byte pitch,byte velocity) { 159 | // remove note from the stack if already there 160 | for(int n = 0;n0){ 172 | // if pitch corresponds to last note in the stack 173 | // set syncPhaseInc to previous note (if exists) 174 | if( pitch == notes_stack.get(notes_stack.size()-1)){ 175 | notes_stack.pop(); 176 | if(notes_stack.size()>0){ 177 | uint8_t previous = notes_stack.get(notes_stack.size()-1); 178 | syncPhaseInc = midiTable[previous]; 179 | } 180 | } 181 | } 182 | 183 | // remove notes from the stack 184 | for(int n = 0;n> 7) & 0xff; 245 | if (grainPhaseAcc & 0x8000) value = ~value; 246 | // Multiply by current grain amplitude to get sample 247 | output = value * (grainAmp >> 8); 248 | 249 | // Repeat for second grain 250 | value = (grain2PhaseAcc >> 7) & 0xff; 251 | if (grain2PhaseAcc & 0x8000) value = ~value; 252 | output += value * (grain2Amp >> 8); 253 | 254 | // Make the grain amplitudes decay by a factor every sample (exponential decay) 255 | grainAmp -= (grainAmp >> 8) * grainDecay; 256 | grain2Amp -= (grain2Amp >> 8) * grain2Decay; 257 | 258 | // Scale output to the available range,clipping if necessary 259 | output >>= 9; 260 | if (output > 255) output = 255; 261 | 262 | // Output to PWM (this is faster than using analogWrite) 263 | PWM_VALUE = output; 264 | } 265 | -------------------------------------------------------------------------------- /midi2cv_recorder/midi2cv_recorder.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct SeqNote{ 4 | byte note; 5 | byte velocity; 6 | uint32_t time; 7 | }; 8 | 9 | #define SEQ_COUNT 1000 10 | #define MAX_SEQ_COUNT (UINT32_MAX-1) //in millis 11 | 12 | byte command; 13 | byte note; 14 | byte velocity; 15 | volatile uint32_t freq = 0; 16 | SeqNote seq[SEQ_COUNT]; 17 | volatile uint32_t seq_index = 0; 18 | volatile uint32_t seq_last_index = 0; 19 | volatile uint32_t seq_counter = 0; 20 | volatile uint32_t seq_length = 0; 21 | volatile bool seq_on = false; 22 | volatile bool prepared_to_rec = false; 23 | volatile bool rec_on = false; 24 | 25 | 26 | int myLed = 13; 27 | bool ledOn = false; 28 | 29 | void seqHandler(){ 30 | if(rec_on){ 31 | if(seq_counter>=seq_length){ 32 | Serial.println("rec overload 1"); 33 | 34 | stopRec(); 35 | startSeq(); 36 | } 37 | seq_counter++; 38 | } 39 | 40 | 41 | if(seq_on){ 42 | if(seq_counter>=seq_length){ 43 | seq_counter=0; 44 | seq_index=0; 45 | Serial.println("loop seq"); 46 | return; 47 | } 48 | 49 | if(seq_counter>=seq[seq_index].time){ 50 | changeFreq(seq[seq_index].note); 51 | if(seq_index < seq_last_index) 52 | seq_index++; 53 | } 54 | seq_counter++; 55 | } 56 | 57 | 58 | } 59 | 60 | void changeFreq(int note){ 61 | static int last_note = 0; 62 | 63 | if(note != last_note){ 64 | last_note = note; 65 | Serial.println("change freq"); 66 | int val = map(note, 48, 96, 0, 4095); 67 | analogWrite(DAC0, val); 68 | 69 | } 70 | 71 | } 72 | 73 | 74 | void setup() { 75 | 76 | 77 | analogWriteResolution(12); 78 | Serial.begin(9600); 79 | Serial1.begin(31250); 80 | analogWrite(DAC0, 0); 81 | Serial.println("started"); 82 | 83 | pinMode(myLed, OUTPUT); 84 | Timer3.attachInterrupt(seqHandler); 85 | Timer3.start(1000); // Calls every 1ms 86 | 87 | } 88 | 89 | 90 | void loop () { 91 | 92 | if (Serial1.available()>2){ 93 | 94 | int count = Serial1.available();//read first byte 95 | command = Serial1.read();//read first byte 96 | note = Serial1.read();//read next byte 97 | velocity = Serial1.read();//read final byte 98 | 99 | 100 | // note on message starting 101 | if (command== 144){ 102 | Serial.print(command); 103 | Serial.print(" - "); 104 | Serial.print(note); 105 | Serial.print(" - "); 106 | Serial.print(velocity); 107 | Serial.print(" - "); 108 | Serial.println(count); 109 | 110 | if (note >=48 && note <=96){ 111 | if(prepared_to_rec) 112 | startRec(); 113 | 114 | if(rec_on){ 115 | SeqNote seqn = { note , velocity , seq_counter }; 116 | seq[seq_index] = seqn; 117 | seq_last_index = seq_index; 118 | seq_index++; 119 | 120 | if (seq_index>=SEQ_COUNT){ 121 | Serial.println("rec overload 2"); 122 | stopRec(); 123 | startSeq(); 124 | } 125 | } 126 | 127 | changeFreq(note); 128 | } 129 | } 130 | 131 | // note off message starting starting 132 | if (command== 128){ 133 | } 134 | 135 | 136 | //transport 137 | if (command== 176){ 138 | //rec button 139 | if (note== 117 && velocity>0){ 140 | prepared_to_rec= true; 141 | } 142 | //play button 143 | if (note== 115 && velocity>0){ 144 | if(prepared_to_rec) 145 | startRec(); 146 | else 147 | startSeq(); 148 | } 149 | //stop button 150 | if (note== 114 && velocity>0){ 151 | if(seq_on){ 152 | stopSeq(); 153 | } 154 | if(rec_on){ 155 | stopRec(); 156 | } 157 | } 158 | } 159 | 160 | 161 | 162 | } 163 | 164 | 165 | } 166 | 167 | 168 | void startRec(){ 169 | Serial.println("start recording"); 170 | seq_length = MAX_SEQ_COUNT; 171 | rec_on = true; 172 | seq_counter = 0; 173 | seq_index = 0; 174 | prepared_to_rec= false; 175 | 176 | } 177 | 178 | void stopRec(){ 179 | Serial.println("stop recording"); 180 | seq_length = seq_counter; 181 | rec_on = false; 182 | seq_counter=0; 183 | seq_index=0; 184 | prepared_to_rec= false; 185 | } 186 | 187 | void startSeq(){ 188 | Serial.println("start seq"); 189 | seq_on = true; 190 | seq_counter=0; 191 | seq_index=0; 192 | } 193 | 194 | 195 | void stopSeq(){ 196 | Serial.println("stop seq"); 197 | seq_on = false; 198 | prepared_to_rec= false; 199 | } 200 | 201 | -------------------------------------------------------------------------------- /midiBLE/midiBLE.ino: -------------------------------------------------------------------------------- 1 | // set midi channel to be sent 2 | int channel = 10; 3 | // set the octave height 4 | int octave = 2; 5 | 6 | int notas[] = {0,1,2,3,4,5,6,7}; 7 | 8 | 9 | void setup() { 10 | 11 | Serial.begin(9600); 12 | 13 | } 14 | 15 | void loop() { 16 | 17 | for(int i=0;i<8;i++){ 18 | noteOn(notas[i], 100); 19 | delay(1500); 20 | noteOff(notas[i]); 21 | delay(500); 22 | } 23 | 24 | } 25 | 26 | 27 | 28 | 29 | // plays a MIDI note. 30 | void noteOn(int pitch, int velocity) { 31 | int offset= 24; // C1 32 | int note = offset + pitch + octave * 12; 33 | Serial.write(0x90 + channel - 1 ); 34 | Serial.write(note); 35 | Serial.write(velocity); 36 | } 37 | 38 | void noteOff(int pitch) { 39 | noteOn(pitch, 0); 40 | } 41 | 42 | 43 | -------------------------------------------------------------------------------- /midiblue/midiblue.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | SoftwareSerial softSerial(2,3); 4 | struct BleSettings : public midi::DefaultSettings 5 | { 6 | static const long BaudRate = 9600; 7 | }; 8 | //MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial, midiB, BleSettings); 9 | MIDI_CREATE_CUSTOM_INSTANCE(SoftwareSerial, softSerial, midiB, BleSettings); 10 | 11 | void handleNoteOn(byte channel, byte pitch, byte velocity) 12 | { 13 | digitalWrite(LED_BUILTIN,HIGH); 14 | } 15 | 16 | void handleNoteOff(byte channel, byte pitch, byte velocity) 17 | { 18 | digitalWrite(LED_BUILTIN,LOW); 19 | 20 | } 21 | 22 | 23 | void setup() 24 | { 25 | pinMode(LED_BUILTIN, OUTPUT); 26 | 27 | // Connect the handleNoteOn function to the library, 28 | // so it is called upon reception of a NoteOn. 29 | midiB.setHandleNoteOn(handleNoteOn); // Put only the name of the function 30 | 31 | // Do the same for NoteOffs 32 | midiB.setHandleNoteOff(handleNoteOff); 33 | 34 | // Initiate MIDI communications, listen to all channels 35 | midiB.begin(MIDI_CHANNEL_OMNI); 36 | } 37 | 38 | void loop() 39 | { 40 | // Call MIDI.read the fastest you can for real-time performance. 41 | midiB.read(); 42 | } 43 | -------------------------------------------------------------------------------- /pro53/pro53.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | const int controlsCount = 4; 7 | const int statesCount = 12; 8 | 9 | // the LED 10 | const int ledPins[controlsCount] = { 7, 11, A1 , A5}; 11 | uint8_t state = 0; 12 | uint8_t ledStates[statesCount][controlsCount]; 13 | uint8_t encodersValue[statesCount][controlsCount]; 14 | 15 | 16 | ClickEncoder mainEncoder = ClickEncoder(2, 3, 0, 4); 17 | 18 | ClickEncoder encoders[controlsCount] = { 19 | ClickEncoder(4, 5), 20 | ClickEncoder(8, 9), 21 | ClickEncoder(12, 13), 22 | ClickEncoder(A2, A3), 23 | }; 24 | 25 | ClickButton buttons[controlsCount] = { 26 | ClickButton (6, HIGH), 27 | ClickButton (10, HIGH), 28 | ClickButton (A0, HIGH), 29 | ClickButton (A4, LOW, HIGH), //button3 is active low 30 | }; 31 | 32 | void timerIsr() { 33 | mainEncoder.service(); 34 | for (int i=0; ipin = pin; 12 | this->dampMs = dampMs; 13 | this->minOutputValue = minOutputValue; 14 | this->maxOutputValue = maxOutputValue; 15 | 16 | pinMode(pin, INPUT); 17 | 18 | } 19 | 20 | 21 | int AutoRange::read() { 22 | long curMillis = millis(); 23 | float t = (curMillis-lastMillis)/ ((float)dampMs); 24 | lastMillis = curMillis; 25 | 26 | // read the analog in value: 27 | int rawValue = analogRead(pin); 28 | 29 | //bypass lerp the first time 30 | if ( value == -1) 31 | value = rawValue; 32 | else 33 | value = lerp( value, rawValue, t); 34 | 35 | if ( value < minValue) 36 | minValue = value; 37 | 38 | if ( value > maxValue) 39 | maxValue = value; 40 | 41 | // map it to the range of the analog out: 42 | outputValue = map(value, minValue, maxValue, minOutputValue, maxOutputValue); 43 | return outputValue; 44 | 45 | } 46 | 47 | void AutoRange::debug(){ 48 | Serial.print(minValue); 49 | Serial.print(" - \t - "); 50 | Serial.print(value); 51 | Serial.print(" - \t - "); 52 | Serial.print(maxValue); 53 | Serial.print(" - \t - "); 54 | Serial.print(minValue); 55 | Serial.print(" - \t::: - "); 56 | Serial.print(minOutputValue); 57 | Serial.print(" - \t - "); 58 | Serial.print(outputValue); 59 | Serial.print(" - \t - "); 60 | Serial.print(maxOutputValue); 61 | Serial.println(""); 62 | } 63 | 64 | -------------------------------------------------------------------------------- /windController/AutoRange.h: -------------------------------------------------------------------------------- 1 | #ifndef AutoRange_h 2 | #define AutoRange_h 3 | 4 | #include "Arduino.h" 5 | 6 | // library interface description 7 | class AutoRange 8 | { 9 | public: 10 | AutoRange(int pin, int dampMs, int minOutputValue,int maxOutputValue); 11 | int read(); 12 | int value = -1; 13 | int outputValue; 14 | int minValue = 1023; // yes, these are correct 15 | int maxValue = 0; // to let it autorange later 16 | void debug(); 17 | private: 18 | 19 | float lerp(float v0, float v1, float t) { 20 | return v0 + t * (v1 - v0); 21 | } 22 | 23 | int minOutputValue; 24 | int maxOutputValue; 25 | 26 | int pin; 27 | long lastMillis = 0; 28 | int dampMs = 200; 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /windController/windController.ino: -------------------------------------------------------------------------------- 1 | #include "AutoRange.h" 2 | 3 | int jumperPins[]= {8,9,10,11}; 4 | int lastValues[4]; 5 | 6 | AutoRange ar0 = AutoRange(A0,// analog pin 7 | 200, // interpolation time in ms 8 | 0, // min output value 9 | 127); // max output value 10 | AutoRange ar1 = AutoRange(A1,// analog pin 11 | 200, // interpolation time in ms 12 | 0, // min output value 13 | 127); // max output value 14 | AutoRange ar2 = AutoRange(A2,// analog pin 15 | 200, // interpolation time in ms 16 | 0, // min output value 17 | 127); // max output value 18 | AutoRange ar3 = AutoRange(A3,// analog pin 19 | 200, // interpolation time in ms 20 | 0, // min output value 21 | 127); // max output value 22 | 23 | 24 | AutoRange ars[4] = {ar0,ar1,ar2,ar3}; 25 | int arPins[] = {A0,A1,A2,A3}; 26 | int ccs[] = {70,71,72,73}; 27 | 28 | void setup() { 29 | for(int i=0;i<4;i++){ 30 | pinMode(jumperPins[i],INPUT_PULLUP); 31 | } 32 | 33 | Serial.begin(9600); 34 | 35 | } 36 | 37 | void loop() { 38 | 39 | int jumper[4]; 40 | 41 | boolean mapping = false; 42 | for(int i=0;i<4;i++){ 43 | jumper[i] = digitalRead(jumperPins[i]); 44 | if(jumper[i]==0) 45 | mapping =true; 46 | } 47 | 48 | for(int i=0;i<4;i++){ 49 | int value= ars[i].read(); 50 | if(mapping){ 51 | if(jumper[i]==0){ 52 | sendCc(ccs[i],value); 53 | delay(1000); 54 | } 55 | }else{ 56 | if(lastValues[i] != value){ 57 | sendCc(ccs[i],value); 58 | lastValues[i] = value; 59 | } 60 | } 61 | } 62 | 63 | delay(10); 64 | 65 | } 66 | 67 | 68 | // sends a Control Change 69 | void sendCc(byte cc, byte val) { 70 | //return; 71 | Serial.write(0xB0); 72 | Serial.write(cc); 73 | Serial.write(val); 74 | } 75 | 76 | -------------------------------------------------------------------------------- /ym2612/LinkedList.h: -------------------------------------------------------------------------------- 1 | /* 2 | LinkedList.h - V1.1 - Generic LinkedList implementation 3 | Works better with FIFO, because LIFO will need to 4 | search the entire List to find the last one; 5 | 6 | For instructions, go to https://github.com/ivanseidel/LinkedList 7 | 8 | Created by Ivan Seidel Gomes, March, 2013. 9 | Released into the public domain. 10 | */ 11 | 12 | 13 | #ifndef LinkedList_h 14 | #define LinkedList_h 15 | 16 | template 17 | struct ListNode 18 | { 19 | T data; 20 | ListNode *next; 21 | }; 22 | 23 | template 24 | class LinkedList{ 25 | 26 | protected: 27 | int _size; 28 | ListNode *root; 29 | ListNode *last; 30 | 31 | // Helps "get" method, by saving last position 32 | ListNode *lastNodeGot; 33 | int lastIndexGot; 34 | // isCached should be set to FALSE 35 | // everytime the list suffer changes 36 | bool isCached; 37 | 38 | ListNode* getNode(int index); 39 | 40 | public: 41 | LinkedList(); 42 | ~LinkedList(); 43 | 44 | /* 45 | Returns current size of LinkedList 46 | */ 47 | virtual int size(); 48 | /* 49 | Adds a T object in the specified index; 50 | Unlink and link the LinkedList correcly; 51 | Increment _size 52 | */ 53 | virtual bool add(int index, T); 54 | /* 55 | Adds a T object in the end of the LinkedList; 56 | Increment _size; 57 | */ 58 | virtual bool add(T); 59 | /* 60 | Adds a T object in the start of the LinkedList; 61 | Increment _size; 62 | */ 63 | virtual bool unshift(T); 64 | /* 65 | Set the object at index, with T; 66 | Increment _size; 67 | */ 68 | virtual bool set(int index, T); 69 | /* 70 | Remove object at index; 71 | If index is not reachable, returns false; 72 | else, decrement _size 73 | */ 74 | virtual T remove(int index); 75 | /* 76 | Remove last object; 77 | */ 78 | virtual T pop(); 79 | /* 80 | Remove first object; 81 | */ 82 | virtual T shift(); 83 | /* 84 | Get the index'th element on the list; 85 | Return Element if accessible, 86 | else, return false; 87 | */ 88 | virtual T get(int index); 89 | 90 | /* 91 | Clear the entire array 92 | */ 93 | virtual void clear(); 94 | 95 | }; 96 | 97 | // Initialize LinkedList with false values 98 | template 99 | LinkedList::LinkedList() 100 | { 101 | root=NULL; 102 | last=NULL; 103 | _size=0; 104 | 105 | lastNodeGot = root; 106 | lastIndexGot = 0; 107 | isCached = false; 108 | } 109 | 110 | // Clear Nodes and free Memory 111 | template 112 | LinkedList::~LinkedList() 113 | { 114 | ListNode* tmp; 115 | while(root!=false) 116 | { 117 | tmp=root; 118 | root=root->next; 119 | delete tmp; 120 | } 121 | last = NULL; 122 | _size=0; 123 | isCached = false; 124 | } 125 | 126 | /* 127 | Actualy "logic" coding 128 | */ 129 | 130 | template 131 | ListNode* LinkedList::getNode(int index){ 132 | 133 | int _pos = 0; 134 | ListNode* current = root; 135 | 136 | // Check if the node trying to get is 137 | // immediatly AFTER the previous got one 138 | if(isCached && lastIndexGot <= index){ 139 | _pos = lastIndexGot; 140 | current = lastNodeGot; 141 | } 142 | 143 | while(_pos < index && current){ 144 | current = current->next; 145 | 146 | _pos++; 147 | } 148 | 149 | // Check if the object index got is the same as the required 150 | if(_pos == index){ 151 | isCached = true; 152 | lastIndexGot = index; 153 | lastNodeGot = current; 154 | 155 | return current; 156 | } 157 | 158 | return false; 159 | } 160 | 161 | template 162 | int LinkedList::size(){ 163 | return _size; 164 | } 165 | 166 | template 167 | bool LinkedList::add(int index, T _t){ 168 | 169 | if(index >= _size) 170 | return add(_t); 171 | 172 | if(index == 0) 173 | return unshift(_t); 174 | 175 | ListNode *tmp = new ListNode(), 176 | *_prev = getNode(index-1); 177 | tmp->data = _t; 178 | tmp->next = _prev->next; 179 | _prev->next = tmp; 180 | 181 | _size++; 182 | isCached = false; 183 | 184 | return true; 185 | } 186 | 187 | template 188 | bool LinkedList::add(T _t){ 189 | 190 | ListNode *tmp = new ListNode(); 191 | tmp->data = _t; 192 | tmp->next = NULL; 193 | 194 | if(root){ 195 | // Already have elements inserted 196 | last->next = tmp; 197 | last = tmp; 198 | }else{ 199 | // First element being inserted 200 | root = tmp; 201 | last = tmp; 202 | } 203 | 204 | _size++; 205 | isCached = false; 206 | 207 | return true; 208 | } 209 | 210 | template 211 | bool LinkedList::unshift(T _t){ 212 | 213 | if(_size == 0) 214 | return add(_t); 215 | 216 | ListNode *tmp = new ListNode(); 217 | tmp->next = root; 218 | tmp->data = _t; 219 | root = tmp; 220 | 221 | _size++; 222 | isCached = false; 223 | 224 | return true; 225 | } 226 | 227 | template 228 | bool LinkedList::set(int index, T _t){ 229 | // Check if index position is in bounds 230 | if(index < 0 || index >= _size) 231 | return false; 232 | 233 | getNode(index)->data = _t; 234 | return true; 235 | } 236 | 237 | template 238 | T LinkedList::pop(){ 239 | if(_size <= 0) 240 | return T(); 241 | 242 | isCached = false; 243 | 244 | if(_size >= 2){ 245 | ListNode *tmp = getNode(_size - 2); 246 | T ret = tmp->next->data; 247 | delete(tmp->next); 248 | tmp->next = NULL; 249 | last = tmp; 250 | _size--; 251 | return ret; 252 | }else{ 253 | // Only one element left on the list 254 | T ret = root->data; 255 | delete(root); 256 | root = NULL; 257 | last = NULL; 258 | _size = 0; 259 | return ret; 260 | } 261 | } 262 | 263 | template 264 | T LinkedList::shift(){ 265 | if(_size <= 0) 266 | return T(); 267 | 268 | if(_size > 1){ 269 | ListNode *_next = root->next; 270 | T ret = root->data; 271 | delete(root); 272 | root = _next; 273 | _size --; 274 | isCached = false; 275 | 276 | return ret; 277 | }else{ 278 | // Only one left, then pop() 279 | return pop(); 280 | } 281 | 282 | } 283 | 284 | template 285 | T LinkedList::remove(int index){ 286 | if (index < 0 || index >= _size) 287 | { 288 | return T(); 289 | } 290 | 291 | if(index == 0) 292 | return shift(); 293 | 294 | if (index == _size-1) 295 | { 296 | return pop(); 297 | } 298 | 299 | ListNode *tmp = getNode(index - 1); 300 | ListNode *toDelete = tmp->next; 301 | T ret = toDelete->data; 302 | tmp->next = tmp->next->next; 303 | delete(toDelete); 304 | _size--; 305 | isCached = false; 306 | return ret; 307 | } 308 | 309 | 310 | template 311 | T LinkedList::get(int index){ 312 | ListNode *tmp = getNode(index); 313 | 314 | return (tmp ? tmp->data : T()); 315 | } 316 | 317 | template 318 | void LinkedList::clear(){ 319 | while(size() > 0) 320 | shift(); 321 | } 322 | 323 | #endif 324 | -------------------------------------------------------------------------------- /ym2612/YM2612.cpp: -------------------------------------------------------------------------------- 1 | #include "YM2612.h" 2 | 3 | 4 | 5 | void YM2612::setup(uint8_t ic_pin, 6 | uint8_t cs_pin, 7 | uint8_t wr_pin, 8 | uint8_t rd_pin, 9 | uint8_t a0_pin, 10 | uint8_t a1_pin, 11 | uint8_t mc_pin, 12 | uint8_t data0_pin, 13 | uint8_t data1_pin, 14 | uint8_t data2_pin, 15 | uint8_t data3_pin, 16 | uint8_t data4_pin, 17 | uint8_t data5_pin, 18 | uint8_t data6_pin, 19 | uint8_t data7_pin) 20 | { 21 | this->ic_pin = ic_pin; 22 | this->cs_pin = cs_pin; 23 | this->wr_pin = wr_pin; 24 | this->rd_pin = rd_pin; 25 | this->a0_pin = a0_pin; 26 | this->a1_pin = a1_pin; 27 | this->mc_pin = mc_pin; 28 | this->data0_pin = data0_pin; 29 | this->data1_pin = data1_pin; 30 | this->data2_pin = data2_pin; 31 | this->data3_pin = data3_pin; 32 | this->data4_pin = data4_pin; 33 | this->data5_pin = data5_pin; 34 | this->data6_pin = data6_pin; 35 | this->data7_pin = data7_pin; 36 | } 37 | 38 | 39 | void YM2612::initialize() { 40 | /* Pins setup */ 41 | pinMode(ic_pin, OUTPUT); 42 | pinMode(cs_pin, OUTPUT); 43 | pinMode(wr_pin, OUTPUT); 44 | pinMode(rd_pin, OUTPUT); 45 | pinMode(a0_pin, OUTPUT); 46 | pinMode(a1_pin, OUTPUT); 47 | pinMode(mc_pin, OUTPUT); 48 | 49 | pinMode(data0_pin, OUTPUT); 50 | pinMode(data1_pin, OUTPUT); 51 | pinMode(data2_pin, OUTPUT); 52 | pinMode(data3_pin, OUTPUT); 53 | pinMode(data4_pin, OUTPUT); 54 | pinMode(data5_pin, OUTPUT); 55 | pinMode(data6_pin, OUTPUT); 56 | pinMode(data7_pin, OUTPUT); 57 | 58 | /* IC, CS, WR and RD HIGH by default */ 59 | digitalWrite(ic_pin, HIGH); 60 | digitalWrite(cs_pin, HIGH); 61 | digitalWrite(wr_pin, HIGH); 62 | digitalWrite(rd_pin, HIGH); 63 | 64 | /* A0 and A1 LOW by default */ 65 | digitalWrite(a0_pin, LOW); 66 | digitalWrite(a1_pin, LOW); 67 | 68 | /* F_CPU / 2 clock generation */ 69 | TCCR1A = _BV(COM1A0); /* Toggle OCA1 on compare match */ 70 | TCCR1B = _BV(WGM12) | _BV(CS10); /* CTC mode with prescaler /1 */ 71 | TCCR1C = 0; /* Flag reset */ 72 | TCNT1 = 0; /* Counter reset */ 73 | OCR1A = 0; /* Divide base clock by two */ 74 | 75 | /* Reset YM2612 */ 76 | digitalWrite(ic_pin, LOW); 77 | delay(10); 78 | digitalWrite(ic_pin, HIGH); 79 | delay(10); 80 | 81 | 82 | setDefaults(); 83 | 84 | } 85 | 86 | 87 | 88 | 89 | void YM2612::setDefaults() { 90 | 91 | unison = true; 92 | selected_channel = 1; 93 | operators[0] = true; 94 | operators[1] = true; 95 | operators[2] = true; 96 | operators[3] = true; 97 | 98 | for(int i=0;i<6;i++){ 99 | voices[i].on = false; 100 | keyOff(i); 101 | } 102 | 103 | //channel params 104 | setFeedback(0); 105 | setAlgorithm(7); 106 | setStereo(3); 107 | setAMS(0); 108 | setFMS(7); 109 | //operator params 110 | setAmplitudeModulation(1); 111 | setAttackRate(31); 112 | setDecayRate(31); 113 | setSustainRate(0); 114 | setReleaseRate(8); 115 | setTotalLevel(0); 116 | setSustainLevel(0); 117 | setMultiply(2); 118 | setDetune(3); 119 | setPlaymode(POLY6x1); 120 | 121 | } 122 | 123 | void YM2612::setLFO (int value) { 124 | //mod wheel value (0..8) is used both to enable 125 | // and to set lfo freq 126 | if(value==0){ 127 | setMasterParameter( YM_MA_LFO_E, 0); 128 | }else{ 129 | setMasterParameter( YM_MA_LFO_E, 1); 130 | setMasterParameter( YM_MA_LFO_F, value-1); 131 | } 132 | } 133 | 134 | void YM2612::sendData(uint8_t data) { 135 | digitalWrite(cs_pin, LOW); 136 | 137 | digitalWrite(data0_pin, ( (data >> 0) & 0x01) ); 138 | digitalWrite(data1_pin, ( (data >> 1) & 0x01) ); 139 | digitalWrite(data2_pin, ( (data >> 2) & 0x01) ); 140 | digitalWrite(data3_pin, ( (data >> 3) & 0x01) ); 141 | digitalWrite(data4_pin, ( (data >> 4) & 0x01) ); 142 | digitalWrite(data5_pin, ( (data >> 5) & 0x01) ); 143 | digitalWrite(data6_pin, ( (data >> 6) & 0x01) ); 144 | digitalWrite(data7_pin, ( (data >> 7) & 0x01) ); 145 | 146 | delayMicroseconds(2); //it was 1 before 147 | digitalWrite(wr_pin, LOW); 148 | delayMicroseconds(5); 149 | digitalWrite(wr_pin, HIGH); 150 | delayMicroseconds(5); 151 | digitalWrite(cs_pin, HIGH); 152 | } 153 | 154 | 155 | void YM2612::setRegister(uint8_t part, uint8_t reg, uint8_t data) { 156 | digitalWrite(a1_pin, part); 157 | digitalWrite(a0_pin, LOW); 158 | sendData(reg); 159 | digitalWrite(a0_pin, HIGH); 160 | sendData(data); 161 | } 162 | 163 | void YM2612::setMasterParameter(int reg_offset, int val_size, int val_shift, int val) { 164 | uint8_t* p = (uint8_t *) ( &master) + reg_offset; 165 | 166 | *(p) &= ~(mask(val_size) << val_shift); //clean 167 | *(p) |= ((mask(val_size) & val) << val_shift); //write 168 | setRegister(0, YM_MASTER_ADDR + reg_offset, *(p)); 169 | 170 | } 171 | 172 | void YM2612::setChannelParameter(int reg_offset, int val_size, int val_shift, int val) { 173 | 174 | if (unison) { 175 | for (int i = 0; i < 6; i++) 176 | setChannelParameter(i, reg_offset, val_size, val_shift, val); 177 | } else { 178 | setChannelParameter(selected_channel, reg_offset, val_size, val_shift, val); 179 | } 180 | 181 | } 182 | 183 | void YM2612::setChannelParameter(int chan, int reg_offset, int val_size, int val_shift, int val) { 184 | 185 | int channel_part = chan / 3; 186 | uint8_t* p = (uint8_t *) ( &channels[channel_part]) + reg_offset; 187 | int channel_offset = chan % 3; //which of the 12 registers 188 | 189 | *(p + channel_offset) &= ~(mask(val_size) << val_shift); //clean 190 | *(p + channel_offset) |= ((mask(val_size) & val) << val_shift); //write 191 | setRegister(channel_part, YM_CHN_ADDR + reg_offset + channel_offset, *(p + channel_offset)); 192 | 193 | } 194 | 195 | 196 | void YM2612::setOperatorParameter(int reg_offset, int val_size, int val_shift, int val) { 197 | 198 | if (unison) { 199 | for (int i = 0; i < 6; i++) 200 | setOperatorParameter(i, reg_offset, val_size, val_shift, val); 201 | } else { 202 | setOperatorParameter(selected_channel, reg_offset, val_size, val_shift, val); 203 | } 204 | 205 | } 206 | 207 | 208 | void YM2612::setOperatorParameter(int chan, int reg_offset, int val_size, int val_shift, int val) { 209 | for (int i = 0; i < 4; i++) 210 | if (operators[i]) 211 | setOperatorParameter(chan, i, reg_offset, val_size, val_shift, val); 212 | } 213 | 214 | void YM2612::setOperatorParameter(int chan,int oper, int reg_offset, int val_size, int val_shift, int val) { 215 | int channel_part = chan / 3; 216 | uint8_t* p = (uint8_t *) ( &channels[channel_part]) + reg_offset; 217 | int op_offset = chan % 3 + oper * 4; //which of the 12 registers 218 | *(p + op_offset) &= ~(mask(val_size) << val_shift); //clean 219 | *(p + op_offset) |= ((mask(val_size) & val) << val_shift); //write 220 | setRegister(channel_part, YM_CHN_ADDR + reg_offset + op_offset, *(p + op_offset)); 221 | } 222 | 223 | 224 | 225 | 226 | void YM2612::setPlaymode(int value) { 227 | playmode = (playmode_t)value; 228 | 229 | // kill all voices 230 | for(int i = 0; i<6;i++){ 231 | voices[i].on = false; 232 | keyOff(i); 233 | } 234 | notes_stack0.clear(); 235 | notes_stack1.clear(); 236 | 237 | } 238 | 239 | void YM2612::noteOn(byte channel, byte pitch, byte velocity) 240 | { 241 | UNUSED(channel); 242 | UNUSED(velocity); 243 | 244 | 245 | switch(playmode) { 246 | 247 | case MONO1x6: 248 | { 249 | notes_stack0.add(pitch); 250 | for(int i=0;i<6;i++){ 251 | voices[i].on = true; 252 | voices[i].note = pitch; 253 | setNote(i,pitch); 254 | if(notes_stack0.size()==1) //trigger on first note only 255 | keyOn(i); 256 | } 257 | 258 | break; 259 | } 260 | case POLY6x1: 261 | { 262 | int index = -1; 263 | 264 | //attempts to find a free voice 265 | for(int i=0;i<6;i++) 266 | if(!voices[i].on){ 267 | index = i; 268 | voices_order[voices_order_index] = i; 269 | break; 270 | } 271 | 272 | // no free voice, just kill the oldest 273 | if(index==-1) 274 | index = voices_order[voices_order_index]; 275 | 276 | voices_order_index++; 277 | voices_order_index %=6; 278 | 279 | voices[index].on = true; 280 | voices[index].note = pitch; 281 | setNote(index,pitch); 282 | keyOn(index); 283 | break; 284 | } 285 | 286 | case POLY3x2: 287 | { 288 | int index = -1; 289 | int concurrent_voices = 2; 290 | 291 | //attempts to find a free voice 292 | for(int i=0;i<6;i+=concurrent_voices) 293 | if(!voices[i].on){ 294 | index = i; 295 | voices_order[voices_order_index] = i; 296 | break; 297 | } 298 | 299 | // no free voice, just kill the oldest 300 | if(index==-1) 301 | index = voices_order[voices_order_index]; 302 | 303 | voices_order_index+=concurrent_voices; 304 | voices_order_index %=6; 305 | 306 | for(int i=0;i0){ 394 | if( pitch == notes_stack0.get(notes_stack0.size()-1)){ 395 | notes_stack0.pop(); 396 | if(notes_stack0.size()>0){ 397 | uint8_t previous = notes_stack0.get(notes_stack0.size()-1); 398 | for(int i=0;i<6;i++){ 399 | voices[i].note = previous; 400 | setNote(i,previous); 401 | // dont trigger key on 402 | } 403 | } 404 | }else{ 405 | // do nothing 406 | // only remove note from the stack 407 | for(int n = 0;n= 2048) { 528 | frequency /= 2; 529 | block++; 530 | } 531 | freq = (uint16_t)frequency; 532 | 533 | //setMasterParameter( YM_MA_OP_CHAN, 0xF0 + ((channel/3) * 4 + channel%3 ) ); 534 | 535 | setRegister(chan/3, 0xA4+(chan%3), ((freq >> 8) & mask(3)) | ( ( block & mask(3) ) << 3) ); // Set frequency 536 | setRegister(chan/3, 0xA0+(chan%3), freq); 537 | 538 | } 539 | 540 | 541 | 542 | void YM2612::keyOn(uint8_t chan) { 543 | setMasterParameter( YM_MA_OP_CHAN, 0xF0 + ((chan/3) * 4 + chan%3 ) ); 544 | } 545 | 546 | void YM2612::keyOff(uint8_t chan) { 547 | setMasterParameter( YM_MA_OP_CHAN, 0x00 +((chan/3) * 4 + chan%3 ) ); 548 | } 549 | 550 | void YM2612::update(){ 551 | } 552 | 553 | -------------------------------------------------------------------------------- /ym2612/YM2612.h: -------------------------------------------------------------------------------- 1 | #ifndef YM2612_h 2 | #define YM2612_h 3 | 4 | #include "Arduino.h" 5 | #include 6 | #include "LinkedList.h" 7 | 8 | #define UNUSED(x) (void)(x) 9 | #define YM_MASTER_ADDR (0x22) 10 | #define YM_CHN_ADDR (0x30) 11 | 12 | #define YM_MA_LFO_E offsetof(Master_t,LFO), 1, 3 13 | #define YM_MA_LFO_F offsetof(Master_t,LFO), 3, 0 14 | #define YM_MA_CH3_M offsetof(Master_t,CHAN3_MODE_TIMERS), 2, 6 15 | #define YM_MA_OP_CHAN offsetof(Master_t,OP_CHAN), 8, 0 16 | 17 | #define YM_OP_DT1 offsetof(Channels_t,DT1_MUL), 3, 4 18 | #define YM_OP_MUL offsetof(Channels_t,DT1_MUL), 4, 0 19 | #define YM_OP_TL offsetof(Channels_t,TL), 7, 0 20 | #define YM_OP_RS offsetof(Channels_t,RS_AR), 2, 6 21 | #define YM_OP_AR offsetof(Channels_t,RS_AR), 5, 0 22 | #define YM_OP_AM offsetof(Channels_t,AM_D1R), 1, 7 23 | #define YM_OP_D1R offsetof(Channels_t,AM_D1R), 5, 0 24 | #define YM_OP_D2R offsetof(Channels_t,D2R), 5, 0 25 | #define YM_OP_D1L offsetof(Channels_t,D1L_RR), 4, 4 26 | #define YM_OP_RR offsetof(Channels_t,D1L_RR), 4, 0 27 | #define YM_OP_SSG_EG offsetof(Channels_t,SSG_EG), 8, 0 28 | 29 | #define YM_CH_FB offsetof(Channels_t,FB_ALG), 3, 3 30 | #define YM_CH_ALG offsetof(Channels_t,FB_ALG), 3, 0 31 | #define YM_CH_L_R offsetof(Channels_t,L_R_AMS_FMS), 2, 6 32 | #define YM_CH_AMS offsetof(Channels_t,L_R_AMS_FMS), 2, 4 33 | #define YM_CH_FMS offsetof(Channels_t,L_R_AMS_FMS), 3, 0 34 | 35 | #define mask(s) (~(~0<0);} 108 | void selectOperator(int op, int value) {operators[op] = (value>0);} 109 | 110 | //master params 111 | void setLFO (int value); 112 | void setChan3Mode (int value) { setMasterParameter( YM_MA_CH3_M, value);} 113 | 114 | //channel params 115 | void setFeedback (int value) { setChannelParameter( YM_CH_FB, value);} 116 | void setAlgorithm (int value) { setChannelParameter( YM_CH_ALG, value);} 117 | void setStereo (int value) { setChannelParameter( YM_CH_L_R, value);} 118 | void setStereo (int l, int r) { setStereo((l<<1)|r);} 119 | void setAMS (int value) { setChannelParameter( YM_CH_AMS, value);} 120 | void setFMS (int value) { setChannelParameter( YM_CH_FMS, value);} 121 | //operator params 122 | void setAmplitudeModulation (int value) { setOperatorParameter( YM_OP_AM, (value>0));} 123 | void setAttackRate (int value) { setOperatorParameter( YM_OP_AR, value);} 124 | void setDecayRate (int value) { setOperatorParameter( YM_OP_D1R, value);} 125 | void setSustainRate (int value) { setOperatorParameter( YM_OP_D2R, value);} 126 | void setReleaseRate (int value) { setOperatorParameter( YM_OP_RR, value);} 127 | void setTotalLevel (int value) { setOperatorParameter( YM_OP_TL, value);} 128 | void setSustainLevel (int value) { setOperatorParameter( YM_OP_D1L, value);} 129 | void setMultiply (int value) { setOperatorParameter( YM_OP_MUL, value);} 130 | void setDetune (int value) { setOperatorParameter( YM_OP_DT1, value);} 131 | void setRateScaling (int value) { setOperatorParameter( YM_OP_RS, value);} 132 | void setSSG_EG (int value) { setOperatorParameter( YM_OP_SSG_EG, value);} 133 | 134 | void noteOn(byte chan, byte pitch, byte velocity); 135 | void noteOff(byte chan, byte pitch, byte velocity); 136 | void pitchBend(byte channel, int bend); 137 | void update(); 138 | 139 | private: 140 | voice_t voices[6]; 141 | uint8_t voices_order[6]; 142 | uint8_t voices_order_index = 0; 143 | 144 | 145 | LinkedList notes_stack0 = LinkedList(); 146 | LinkedList voices_stack0 = LinkedList(); 147 | LinkedList notes_stack1 = LinkedList(); 148 | LinkedList voices_stack1 = LinkedList(); 149 | uint8_t splitNote = 60; 150 | int pitchBendValue = 0; 151 | 152 | playmode_t playmode; 153 | uint8_t selected_channel; 154 | bool operators[4]; 155 | bool unison; 156 | Master_t master; 157 | Channels_t channels[2]; 158 | uint8_t ic_pin; 159 | uint8_t cs_pin; 160 | uint8_t wr_pin; 161 | uint8_t rd_pin; 162 | uint8_t a0_pin; 163 | uint8_t a1_pin; 164 | uint8_t mc_pin; 165 | uint8_t data0_pin; 166 | uint8_t data1_pin; 167 | uint8_t data2_pin; 168 | uint8_t data3_pin; 169 | uint8_t data4_pin; 170 | uint8_t data5_pin; 171 | uint8_t data6_pin; 172 | uint8_t data7_pin; 173 | uint8_t channelPart(); 174 | uint8_t channelOffset(); 175 | void sendData(uint8_t data); 176 | void setRegister(uint8_t part, uint8_t reg, uint8_t data); 177 | void setMasterParameter(int reg_offset, int val_size, int val_shift,int val); 178 | void setChannelParameter(int chan,int reg_offset, int val_size, int val_shift,int val); 179 | void setChannelParameter(int reg_offset, int val_size, int val_shift,int val); 180 | void setOperatorParameter(int reg_offset, int val_size, int val_shift,int val); 181 | void setOperatorParameter(int chan,int reg_offset, int val_size, int val_shift,int val); 182 | void setOperatorParameter(int chan,int oper, int reg_offset, int val_size, int val_shift, int val); 183 | 184 | void setDefaults(); 185 | void setNote(uint8_t channel, uint8_t note); 186 | void setFrequency(uint8_t channel, float frequency); 187 | void setSupplementaryFrequency(uint8_t channel, uint8_t oper, float frequency); 188 | void keyOn(uint8_t channel); 189 | void keyOff(uint8_t channel); 190 | 191 | 192 | static float noteToFrequency(uint8_t note); 193 | 194 | 195 | }; 196 | 197 | 198 | #endif 199 | 200 | 201 | 202 | 203 | /* 204 | 205 | from http://www.smspower.org/maxim/Documents/YM2612#reg27 206 | 207 | Part I memory map 208 | ================= 209 | 210 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 211 | | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | | 212 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 213 | | 22H | | | | | LFO enable | LFO frequency | | | 214 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 215 | | 24H | Timer A MSBs | | | | | | | | 216 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 217 | | 25H | | | | | | | Timer A LSBs | | 218 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 219 | | 26H | Timer B | | | | | | | | 220 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 221 | | 27H | Ch3 mode | | Reset B | Reset A | Enable B | Enable A | Load B | Load A | 222 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 223 | | 28H | Operator | | | | | Channel | | | 224 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 225 | | 29H | | | | | | | | | 226 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 227 | | 2AH | DAC | | | | | | | | 228 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 229 | | 2BH | DAC en | | | | | | | | 230 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 231 | | | | | | | | | | | 232 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 233 | | 30H+ | | DT1 | | | MUL | | | | 234 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 235 | | 40H+ | | TL | | | | | | | 236 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 237 | | 50H+ | RS | | | AR | | | | | 238 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 239 | | 60H+ | AM | | | D1R | | | | | 240 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 241 | | 70H+ | | | | D2R | | | | | 242 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 243 | | 80H+ | D1L | | | | RR | | | | 244 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 245 | | 90H+ | | | | | SSG-EG | | | | 246 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 247 | | | | | | | | | | | 248 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 249 | | A0H+ | Frequency number LSB | | | | | | | | 250 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 251 | | A4H+ | | | Block | | | Frequency Number MSB | | | 252 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 253 | | A8H+ | Ch3 supplementary frequency number | | | | | | | | 254 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 255 | | ACH+ | | | Ch3 supplementary block | | | Ch3 supplementary frequency number | | | 256 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 257 | | B0H+ | | | Feedback | | | Algorithm | | | 258 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 259 | | B4H+ | L | R | AMS | | | FMS | | | 260 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | MIDI Note Number to Frequency Conversion Chart 271 | ============================================== 272 | 273 | Note Frequency Note Frequency Note Frequency 274 | C1 0 8.1757989156 12 16.3515978313 24 32.7031956626 275 | Db 1 8.6619572180 13 17.3239144361 25 34.6478288721 276 | D 2 9.1770239974 14 18.3540479948 26 36.7080959897 277 | Eb 3 9.7227182413 15 19.4454364826 27 38.8908729653 278 | E 4 10.3008611535 16 20.6017223071 28 41.2034446141 279 | F 5 10.9133822323 17 21.8267644646 29 43.6535289291 280 | Gb 6 11.5623257097 18 23.1246514195 30 46.2493028390 281 | G 7 12.2498573744 19 24.4997147489 31 48.9994294977 282 | Ab 8 12.9782717994 20 25.9565435987 32 51.9130871975 283 | A 9 13.7500000000 21 27.5000000000 33 55.0000000000 284 | Bb 10 14.5676175474 22 29.1352350949 34 58.2704701898 285 | B 11 15.4338531643 23 30.8677063285 35 61.7354126570 286 | 287 | C4 36 65.4063913251 48 130.8127826503 60 261.6255653006 288 | Db 37 69.2956577442 49 138.5913154884 61 277.1826309769 289 | D 38 73.4161919794 50 146.8323839587 62 293.6647679174 290 | Eb 39 77.7817459305 51 155.5634918610 63 311.1269837221 291 | E 40 82.4068892282 52 164.8137784564 64 329.6275569129 292 | F 41 87.3070578583 53 174.6141157165 65 349.2282314330 293 | Gb 42 92.4986056779 54 184.9972113558 66 369.9944227116 294 | G 43 97.9988589954 55 195.9977179909 67 391.9954359817 295 | Ab 44 103.8261743950 56 207.6523487900 68 415.3046975799 296 | A 45 110.0000000000 57 220.0000000000 69 440.0000000000 297 | Bb 46 116.5409403795 58 233.0818807590 70 466.1637615181 298 | B 47 123.4708253140 59 246.9416506281 71 493.8833012561 299 | 300 | C7 72 523.2511306012 84 1046.5022612024 96 2093.0045224048 301 | Db 73 554.3652619537 85 1108.7305239075 97 2217.4610478150 302 | D 74 587.3295358348 86 1174.6590716696 98 2349.3181433393 303 | Eb 75 622.2539674442 87 1244.5079348883 99 2489.0158697766 304 | E 76 659.2551138257 88 1318.5102276515 100 2637.0204553030 305 | F 77 698.4564628660 89 1396.9129257320 101 2793.8258514640 306 | Gb 78 739.9888454233 90 1479.9776908465 102 2959.9553816931 307 | G 79 783.9908719635 91 1567.9817439270 103 3135.9634878540 308 | Ab 80 830.6093951599 92 1661.2187903198 104 3322.4375806396 309 | A 81 880.0000000000 93 1760.0000000000 105 3520.0000000000 310 | Bb 82 932.3275230362 94 1864.6550460724 106 3729.3100921447 311 | B 83 987.7666025122 95 1975.5332050245 107 3951.0664100490 312 | 313 | C10 108 4186.0090448096 120 8372.0180896192 314 | Db 109 4434.9220956300 121 8869.8441912599 315 | D 110 4698.6362866785 122 9397.2725733570 316 | Eb 111 4978.0317395533 123 9956.0634791066 317 | E 112 5274.0409106059 124 10548.0818212118 318 | F 113 5587.6517029281 125 11175.3034058561 319 | Gb 114 5919.9107633862 126 11839.8215267723 320 | G 115 6271.9269757080 127 12543.8539514160 321 | Ab 116 6644.8751612791 322 | A 117 7040.0000000000 323 | Bb 118 7458.6201842894 324 | B 119 7902.1328200980 325 | 326 | 327 | NOTES: Middle C is note #60. Frequency is in Hertz. 328 | 329 | Here is C code to calculate an array with all of the above frequencies (ie, so that midi[0], which is midi note #0, is assigned the value of 8.1757989156). Tuning is based upon A=440. 330 | 331 | float midi[127]; 332 | int a = 440; // a is 440 hz... 333 | for (int x = 0; x < 127; ++x) 334 | { 335 | midi[x] = (a / 32) * (2 ^ ((x - 9) / 12)); 336 | } 337 | 338 | 339 | 340 | 341 | */ 342 | -------------------------------------------------------------------------------- /ym2612/ym2612.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "YM2612.h" 3 | 4 | MIDI_CREATE_DEFAULT_INSTANCE(); 5 | YM2612 ym; 6 | bool play_seq = true; 7 | 8 | void handleNoteOn(byte channel, byte pitch, byte velocity) 9 | { 10 | ym.noteOn(channel, pitch, velocity); 11 | } 12 | 13 | void handleNoteOff(byte channel, byte pitch, byte velocity) 14 | { 15 | ym.noteOff(channel, pitch, velocity); 16 | } 17 | 18 | 19 | void handlePitchBend(byte channel, int bend) 20 | { 21 | ym.pitchBend(channel, bend); 22 | } 23 | 24 | 25 | void handleControlChange(byte channel, byte number, byte value) 26 | { 27 | 28 | UNUSED(channel); 29 | 30 | switch(number) { 31 | 32 | // mod wheel 33 | case 1: 34 | ym.setLFO(value); 35 | break; 36 | 37 | // encoders 38 | case 21: 39 | ym.setPlaymode(value); 40 | break; 41 | case 22: 42 | //ym.setAttackRate(value); 43 | break; 44 | case 23: 45 | //ym.setAttackRate(value); 46 | break; 47 | case 24: 48 | //ym.setAttackRate(value); 49 | break; 50 | case 25: 51 | //ym.setAttackRate(value); 52 | break; 53 | case 26: 54 | ym.setStereo(value); 55 | break; 56 | case 27: 57 | ym.setAMS(value); 58 | break; 59 | case 28: 60 | ym.setFMS(value); 61 | break; 62 | 63 | // faders 64 | case 41: 65 | ym.setAttackRate(value); 66 | break; 67 | case 42: 68 | ym.setDecayRate(value); 69 | break; 70 | case 43: 71 | ym.setSustainRate(value); 72 | break; 73 | case 44: 74 | ym.setReleaseRate(value); 75 | break; 76 | case 45: 77 | ym.setTotalLevel(value); 78 | break; 79 | case 46: 80 | ym.setSustainLevel(value); 81 | break; 82 | case 47: 83 | ym.setMultiply(value); 84 | break; 85 | case 48: 86 | ym.setDetune(value); 87 | break; 88 | case 49: 89 | ym.setRateScaling(value); 90 | break; 91 | 92 | // toggles 93 | case 51: 94 | ym.selectOperator(0,value); 95 | break; 96 | case 52: 97 | ym.selectOperator(1,value); 98 | break; 99 | case 53: 100 | ym.selectOperator(2,value); 101 | break; 102 | case 54: 103 | ym.selectOperator(3,value); 104 | break; 105 | case 55: 106 | ym.setAlgorithm(value); 107 | break; 108 | case 56: 109 | ym.selectChannel(value); 110 | break; 111 | case 57: 112 | ym.setUnison(value); 113 | break; 114 | case 58: 115 | ym.setAmplitudeModulation(value); 116 | break; 117 | 118 | // transport 119 | case 112: 120 | break; 121 | case 113: 122 | break; 123 | case 114: 124 | play_seq = false; 125 | break; 126 | case 115: 127 | play_seq = true; 128 | break; 129 | case 116: 130 | break; 131 | case 117: 132 | break; 133 | 134 | } 135 | 136 | } 137 | 138 | 139 | 140 | void setup() { 141 | ym.setup(A5,A4,A3,A2,A1,A0,9, 10,11,2,3,4,5,6,7); 142 | ym.initialize(); 143 | 144 | MIDI.setHandleNoteOn(handleNoteOn); 145 | MIDI.setHandleNoteOff(handleNoteOff); 146 | MIDI.setHandleControlChange(handleControlChange); 147 | MIDI.setHandlePitchBend(handlePitchBend); 148 | 149 | 150 | MIDI.begin(MIDI_CHANNEL_OMNI); 151 | 152 | } 153 | 154 | 155 | 156 | void loop() { 157 | MIDI.read(); 158 | ym.update(); 159 | 160 | if(play_seq) 161 | playSeq(); 162 | 163 | } 164 | 165 | void playSeq(){ 166 | static uint8_t note = 0; 167 | static uint32_t previousMillis = 0; 168 | static uint32_t interval = 700; 169 | static bool pressed = false; 170 | uint32_t currentMillis = millis(); 171 | 172 | if (currentMillis - previousMillis >= interval) { 173 | previousMillis = currentMillis; 174 | if(pressed){ 175 | ym.noteOff(1, 60+note, 0); 176 | note++; 177 | note %=12; 178 | pressed = false; 179 | }else{ 180 | ym.noteOn(1, 60+note, 100); 181 | pressed = true; 182 | } 183 | 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /ym2612_vgi/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diegodorado/arduinoProjects/b868c74205c832cda497d6955b2b17a4909dd3c6/ym2612_vgi/.DS_Store -------------------------------------------------------------------------------- /ym2612_vgi/._.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diegodorado/arduinoProjects/b868c74205c832cda497d6955b2b17a4909dd3c6/ym2612_vgi/._.DS_Store -------------------------------------------------------------------------------- /ym2612_vgi/LinkedList.h: -------------------------------------------------------------------------------- 1 | /* 2 | LinkedList.h - V1.1 - Generic LinkedList implementation 3 | Works better with FIFO, because LIFO will need to 4 | search the entire List to find the last one; 5 | 6 | For instructions, go to https://github.com/ivanseidel/LinkedList 7 | 8 | Created by Ivan Seidel Gomes, March, 2013. 9 | Released into the public domain. 10 | */ 11 | 12 | 13 | #ifndef LinkedList_h 14 | #define LinkedList_h 15 | 16 | template 17 | struct ListNode 18 | { 19 | T data; 20 | ListNode *next; 21 | }; 22 | 23 | template 24 | class LinkedList{ 25 | 26 | protected: 27 | int _size; 28 | ListNode *root; 29 | ListNode *last; 30 | 31 | // Helps "get" method, by saving last position 32 | ListNode *lastNodeGot; 33 | int lastIndexGot; 34 | // isCached should be set to FALSE 35 | // everytime the list suffer changes 36 | bool isCached; 37 | 38 | ListNode* getNode(int index); 39 | 40 | public: 41 | LinkedList(); 42 | ~LinkedList(); 43 | 44 | /* 45 | Returns current size of LinkedList 46 | */ 47 | virtual int size(); 48 | /* 49 | Adds a T object in the specified index; 50 | Unlink and link the LinkedList correcly; 51 | Increment _size 52 | */ 53 | virtual bool add(int index, T); 54 | /* 55 | Adds a T object in the end of the LinkedList; 56 | Increment _size; 57 | */ 58 | virtual bool add(T); 59 | /* 60 | Adds a T object in the start of the LinkedList; 61 | Increment _size; 62 | */ 63 | virtual bool unshift(T); 64 | /* 65 | Set the object at index, with T; 66 | Increment _size; 67 | */ 68 | virtual bool set(int index, T); 69 | /* 70 | Remove object at index; 71 | If index is not reachable, returns false; 72 | else, decrement _size 73 | */ 74 | virtual T remove(int index); 75 | /* 76 | Remove last object; 77 | */ 78 | virtual T pop(); 79 | /* 80 | Remove first object; 81 | */ 82 | virtual T shift(); 83 | /* 84 | Get the index'th element on the list; 85 | Return Element if accessible, 86 | else, return false; 87 | */ 88 | virtual T get(int index); 89 | 90 | /* 91 | Clear the entire array 92 | */ 93 | virtual void clear(); 94 | 95 | }; 96 | 97 | // Initialize LinkedList with false values 98 | template 99 | LinkedList::LinkedList() 100 | { 101 | root=NULL; 102 | last=NULL; 103 | _size=0; 104 | 105 | lastNodeGot = root; 106 | lastIndexGot = 0; 107 | isCached = false; 108 | } 109 | 110 | // Clear Nodes and free Memory 111 | template 112 | LinkedList::~LinkedList() 113 | { 114 | ListNode* tmp; 115 | while(root!=false) 116 | { 117 | tmp=root; 118 | root=root->next; 119 | delete tmp; 120 | } 121 | last = NULL; 122 | _size=0; 123 | isCached = false; 124 | } 125 | 126 | /* 127 | Actualy "logic" coding 128 | */ 129 | 130 | template 131 | ListNode* LinkedList::getNode(int index){ 132 | 133 | int _pos = 0; 134 | ListNode* current = root; 135 | 136 | // Check if the node trying to get is 137 | // immediatly AFTER the previous got one 138 | if(isCached && lastIndexGot <= index){ 139 | _pos = lastIndexGot; 140 | current = lastNodeGot; 141 | } 142 | 143 | while(_pos < index && current){ 144 | current = current->next; 145 | 146 | _pos++; 147 | } 148 | 149 | // Check if the object index got is the same as the required 150 | if(_pos == index){ 151 | isCached = true; 152 | lastIndexGot = index; 153 | lastNodeGot = current; 154 | 155 | return current; 156 | } 157 | 158 | return false; 159 | } 160 | 161 | template 162 | int LinkedList::size(){ 163 | return _size; 164 | } 165 | 166 | template 167 | bool LinkedList::add(int index, T _t){ 168 | 169 | if(index >= _size) 170 | return add(_t); 171 | 172 | if(index == 0) 173 | return unshift(_t); 174 | 175 | ListNode *tmp = new ListNode(), 176 | *_prev = getNode(index-1); 177 | tmp->data = _t; 178 | tmp->next = _prev->next; 179 | _prev->next = tmp; 180 | 181 | _size++; 182 | isCached = false; 183 | 184 | return true; 185 | } 186 | 187 | template 188 | bool LinkedList::add(T _t){ 189 | 190 | ListNode *tmp = new ListNode(); 191 | tmp->data = _t; 192 | tmp->next = NULL; 193 | 194 | if(root){ 195 | // Already have elements inserted 196 | last->next = tmp; 197 | last = tmp; 198 | }else{ 199 | // First element being inserted 200 | root = tmp; 201 | last = tmp; 202 | } 203 | 204 | _size++; 205 | isCached = false; 206 | 207 | return true; 208 | } 209 | 210 | template 211 | bool LinkedList::unshift(T _t){ 212 | 213 | if(_size == 0) 214 | return add(_t); 215 | 216 | ListNode *tmp = new ListNode(); 217 | tmp->next = root; 218 | tmp->data = _t; 219 | root = tmp; 220 | 221 | _size++; 222 | isCached = false; 223 | 224 | return true; 225 | } 226 | 227 | template 228 | bool LinkedList::set(int index, T _t){ 229 | // Check if index position is in bounds 230 | if(index < 0 || index >= _size) 231 | return false; 232 | 233 | getNode(index)->data = _t; 234 | return true; 235 | } 236 | 237 | template 238 | T LinkedList::pop(){ 239 | if(_size <= 0) 240 | return T(); 241 | 242 | isCached = false; 243 | 244 | if(_size >= 2){ 245 | ListNode *tmp = getNode(_size - 2); 246 | T ret = tmp->next->data; 247 | delete(tmp->next); 248 | tmp->next = NULL; 249 | last = tmp; 250 | _size--; 251 | return ret; 252 | }else{ 253 | // Only one element left on the list 254 | T ret = root->data; 255 | delete(root); 256 | root = NULL; 257 | last = NULL; 258 | _size = 0; 259 | return ret; 260 | } 261 | } 262 | 263 | template 264 | T LinkedList::shift(){ 265 | if(_size <= 0) 266 | return T(); 267 | 268 | if(_size > 1){ 269 | ListNode *_next = root->next; 270 | T ret = root->data; 271 | delete(root); 272 | root = _next; 273 | _size --; 274 | isCached = false; 275 | 276 | return ret; 277 | }else{ 278 | // Only one left, then pop() 279 | return pop(); 280 | } 281 | 282 | } 283 | 284 | template 285 | T LinkedList::remove(int index){ 286 | if (index < 0 || index >= _size) 287 | { 288 | return T(); 289 | } 290 | 291 | if(index == 0) 292 | return shift(); 293 | 294 | if (index == _size-1) 295 | { 296 | return pop(); 297 | } 298 | 299 | ListNode *tmp = getNode(index - 1); 300 | ListNode *toDelete = tmp->next; 301 | T ret = toDelete->data; 302 | tmp->next = tmp->next->next; 303 | delete(toDelete); 304 | _size--; 305 | isCached = false; 306 | return ret; 307 | } 308 | 309 | 310 | template 311 | T LinkedList::get(int index){ 312 | ListNode *tmp = getNode(index); 313 | 314 | return (tmp ? tmp->data : T()); 315 | } 316 | 317 | template 318 | void LinkedList::clear(){ 319 | while(size() > 0) 320 | shift(); 321 | } 322 | 323 | #endif 324 | -------------------------------------------------------------------------------- /ym2612_vgi/VGI.h: -------------------------------------------------------------------------------- 1 | #ifndef VGI_h 2 | #define VGI_h 3 | 4 | #include 5 | 6 | typedef struct{ 7 | uint8_t Multiplier; // | $00-$0F | 8 | uint8_t Detune; // | $00-$06 | 9 | uint8_t Total_Level; // | $00-$3F | 10 | uint8_t Rate_Scaling; // | $00-$03 | 11 | uint8_t Attack_Rate; // | $00-$1F | 12 | uint8_t Decay_Rate_AM_enable; // | $00-$1F, $80-$9F | 13 | uint8_t Sustain_Rate; // | $00-$1F | 14 | uint8_t Release_Rate; // | $00-$0F | 15 | uint8_t Sustain_Level; // | $00-$0F | 16 | uint8_t SSG_EG; // | $00, $08-$0F | 17 | 18 | } VGI_OP_t; 19 | 20 | 21 | typedef struct{ 22 | uint8_t Algorithm; // | $00-$07 | 23 | uint8_t Feedback; // | $00-$07 | 24 | uint8_t AMD_FMD; // | $00-$07, $10-$17, $20-$27, $30-$37 | 25 | VGI_OP_t ops[4]; 26 | } VGI_t; 27 | 28 | 29 | #endif 30 | 31 | 32 | /* 33 | 34 | 35 | From: https://vgmrips.net/wiki/VGI_File_Format 36 | 37 | VGI File Format 38 | =============== 39 | 40 | +------------+----------------------------+------------------------------------+ 41 | | Hex Offset | Function | Range | 42 | +------------+----------------------------+------------------------------------+ 43 | | 0x00 | Algorithm | $00-$07 | 44 | +------------+----------------------------+------------------------------------+ 45 | | 0x01 | Feedback | $00-$07 | 46 | +------------+----------------------------+------------------------------------+ 47 | | 0x02 | AMD & FMD | $00-$07, $10-$17, $20-$27, $30-$37 | 48 | +------------+----------------------------+------------------------------------+ 49 | | 0x03 | OP0 Multiplier | $00-$0F | 50 | +------------+----------------------------+------------------------------------+ 51 | | 0x04 | OP0 Detune | $00-$06 | 52 | +------------+----------------------------+------------------------------------+ 53 | | 0x05 | OP0 Total Level | $00-$7F | 54 | +------------+----------------------------+------------------------------------+ 55 | | 0x06 | OP0 Rate Scaling | $00-$03 | 56 | +------------+----------------------------+------------------------------------+ 57 | | 0x07 | OP0 Attack Rate | $00-$1F | 58 | +------------+----------------------------+------------------------------------+ 59 | | 0x08 | OP0 Decay Rate & AM enable | $00-$1F, $80-$9F | 60 | +------------+----------------------------+------------------------------------+ 61 | | 0x09 | OP0 Sustain Rate | $00-$1F | 62 | +------------+----------------------------+------------------------------------+ 63 | | 0x0A | OP0 Release Rate | $00-$0F | 64 | +------------+----------------------------+------------------------------------+ 65 | | 0x0B | OP0 Sustain Level | $00-$0F | 66 | +------------+----------------------------+------------------------------------+ 67 | | 0x0C | OP0 SSG-EG | $00, $08-$0F | 68 | +------------+----------------------------+------------------------------------+ 69 | | 0x0D | OP1 Multiplier | $00-$0F | 70 | +------------+----------------------------+------------------------------------+ 71 | | 0x0E | OP1 Detune | $00-$06 | 72 | +------------+----------------------------+------------------------------------+ 73 | | 0x0F | OP1 Total Level | $00-$3F | 74 | +------------+----------------------------+------------------------------------+ 75 | | 0x10 | OP1 Rate Scaling | $00-$03 | 76 | +------------+----------------------------+------------------------------------+ 77 | | 0x11 | OP1 Attack Rate | $00-$1F | 78 | +------------+----------------------------+------------------------------------+ 79 | | 0x12 | OP1 Decay Rate & AM enable | $00-$1F, $80-$9F | 80 | +------------+----------------------------+------------------------------------+ 81 | | 0x13 | OP1 Sustain Rate | $00-$1F | 82 | +------------+----------------------------+------------------------------------+ 83 | | 0x14 | OP1 Release Rate | $00-$0F | 84 | +------------+----------------------------+------------------------------------+ 85 | | 0x15 | OP1 Sustain Level | $00-$0F | 86 | +------------+----------------------------+------------------------------------+ 87 | | 0x16 | OP1 SSG-EG | $00, $08-$0F | 88 | +------------+----------------------------+------------------------------------+ 89 | | 0x17 | OP2 Multiplier | $00-$0F | 90 | +------------+----------------------------+------------------------------------+ 91 | | 0x18 | OP2 Detune | $00-$06 | 92 | +------------+----------------------------+------------------------------------+ 93 | | 0x19 | OP2 Total Level | $00-$3F | 94 | +------------+----------------------------+------------------------------------+ 95 | | 0x1A | OP2 Rate Scaling | $00-$03 | 96 | +------------+----------------------------+------------------------------------+ 97 | | 0x1B | OP2 Attack Rate | $00-$1F | 98 | +------------+----------------------------+------------------------------------+ 99 | | 0x1C | OP2 Decay Rate & AM enable | $00-$1F, $80-$9F | 100 | +------------+----------------------------+------------------------------------+ 101 | | 0x1D | OP2 Sustain Rate | $00-$1F | 102 | +------------+----------------------------+------------------------------------+ 103 | | 0x1E | OP2 Release Rate | $00-$0F | 104 | +------------+----------------------------+------------------------------------+ 105 | | 0x1F | OP2 Sustain Level | $00-$0F | 106 | +------------+----------------------------+------------------------------------+ 107 | | 0x20 | OP2 SSG-EG | $00, $08-$0F | 108 | +------------+----------------------------+------------------------------------+ 109 | | 0x21 | OP3 Multiplier | $00-$0F | 110 | +------------+----------------------------+------------------------------------+ 111 | | 0x22 | OP3 Detune | $00-$06 | 112 | +------------+----------------------------+------------------------------------+ 113 | | 0x23 | OP3 Total Level | $00-$3F | 114 | +------------+----------------------------+------------------------------------+ 115 | | 0x24 | OP3 Rate Scaling | $00-$03 | 116 | +------------+----------------------------+------------------------------------+ 117 | | 0x25 | OP3 Attack Rate | $00-$1F | 118 | +------------+----------------------------+------------------------------------+ 119 | | 0x26 | OP3 Decay Rate & AM enable | $00-$1F, $80-$9F | 120 | +------------+----------------------------+------------------------------------+ 121 | | 0x27 | OP3 Sustain Rate | $00-$1F | 122 | +------------+----------------------------+------------------------------------+ 123 | | 0x28 | OP3 Release Rate | $00-$0F | 124 | +------------+----------------------------+------------------------------------+ 125 | | 0x29 | OP3 Sustain Level | $00-$0F | 126 | +------------+----------------------------+------------------------------------+ 127 | | 0x2A | OP3 SSG-EG | $00, $08-$0F | 128 | +------------+----------------------------+------------------------------------+ 129 | 130 | 131 | 132 | 133 | */ 134 | -------------------------------------------------------------------------------- /ym2612_vgi/YM2612.cpp: -------------------------------------------------------------------------------- 1 | #include "YM2612.h" 2 | 3 | 4 | 5 | void YM2612::setup(uint8_t ic_pin, 6 | uint8_t cs_pin, 7 | uint8_t wr_pin, 8 | uint8_t rd_pin, 9 | uint8_t a0_pin, 10 | uint8_t a1_pin, 11 | uint8_t mc_pin, 12 | uint8_t latch_pin, 13 | uint8_t clock_pin, 14 | uint8_t data_pin, 15 | uint8_t sd_cs_pin) 16 | { 17 | this->ic_pin = ic_pin; 18 | this->cs_pin = cs_pin; 19 | this->wr_pin = wr_pin; 20 | this->rd_pin = rd_pin; 21 | this->a0_pin = a0_pin; 22 | this->a1_pin = a1_pin; 23 | this->mc_pin = mc_pin; 24 | this->latch_pin = latch_pin; 25 | this->clock_pin = clock_pin; 26 | this->data_pin = data_pin; 27 | this->sd_cs_pin = sd_cs_pin; 28 | } 29 | 30 | 31 | void YM2612::initialize() { 32 | /* Pins setup */ 33 | pinMode(ic_pin, OUTPUT); 34 | pinMode(cs_pin, OUTPUT); 35 | pinMode(wr_pin, OUTPUT); 36 | pinMode(rd_pin, OUTPUT); 37 | pinMode(a0_pin, OUTPUT); 38 | pinMode(a1_pin, OUTPUT); 39 | pinMode(mc_pin, OUTPUT); 40 | 41 | pinMode(latch_pin, OUTPUT); 42 | pinMode(clock_pin, OUTPUT); 43 | pinMode(data_pin, OUTPUT); 44 | pinMode(sd_cs_pin, OUTPUT); 45 | 46 | 47 | /* IC, CS, WR and RD HIGH by default */ 48 | digitalWrite(ic_pin, HIGH); 49 | digitalWrite(cs_pin, HIGH); 50 | digitalWrite(wr_pin, HIGH); 51 | digitalWrite(rd_pin, HIGH); 52 | 53 | /* A0 and A1 LOW by default */ 54 | digitalWrite(a0_pin, LOW); 55 | digitalWrite(a1_pin, LOW); 56 | 57 | /* F_CPU / 2 clock generation */ 58 | TCCR1A = _BV(COM1A0); /* Toggle OCA1 on compare match */ 59 | TCCR1B = _BV(WGM12) | _BV(CS10); /* CTC mode with prescaler /1 */ 60 | TCCR1C = 0; /* Flag reset */ 61 | TCNT1 = 0; /* Counter reset */ 62 | OCR1A = 0; /* Divide base clock by two */ 63 | 64 | /* Reset YM2612 */ 65 | digitalWrite(ic_pin, LOW); 66 | delay(10); 67 | digitalWrite(ic_pin, HIGH); 68 | delay(10); 69 | 70 | 71 | setDefaults(); 72 | 73 | } 74 | 75 | 76 | 77 | bool isVgi(char* filename) { 78 | int8_t len = strlen(filename); 79 | return strstr(strlwr(filename + (len - 4)), ".vgi"); 80 | } 81 | 82 | static bool sd_initialized = false; 83 | 84 | void YM2612::loadPatch (){ 85 | File root; 86 | VGI_t inst; 87 | 88 | if (!sd_initialized) { 89 | if (!SD.begin(sd_cs_pin)) 90 | return; 91 | sd_initialized = true; 92 | } 93 | 94 | root = SD.open("/"); 95 | //root.rewindDirectory(); 96 | 97 | 98 | int i = 0; 99 | bool found = false; 100 | while (!found) { 101 | 102 | File entry = root.openNextFile(); 103 | if (! entry) { 104 | // no more files 105 | // fail silently 106 | break; 107 | } 108 | if (isVgi(entry.name())) { 109 | if(i==patch_index){ 110 | found = true; 111 | if (entry.read(&inst,sizeof(inst))) { 112 | 113 | 114 | setUnison(true); 115 | setAMS(0);//inst.AMD_FMD 116 | setFMS(0); 117 | setFeedback(inst.Feedback); 118 | setAlgorithm(inst.Algorithm); 119 | 120 | for(int i=0;i<4;i++){ 121 | 122 | setAttackRate(-1,i,inst.ops[i].Attack_Rate); 123 | setDecayRate(-1,i,inst.ops[i].Decay_Rate_AM_enable); 124 | setSustainRate(-1,i,inst.ops[i].Sustain_Rate); 125 | setReleaseRate(-1,i,inst.ops[i].Release_Rate); 126 | setTotalLevel(-1,i,inst.ops[i].Total_Level); 127 | setSustainLevel(-1,i,inst.ops[i].Sustain_Level); 128 | setMultiply(-1,i,inst.ops[i].Multiplier); 129 | setDetune(-1,i,inst.ops[i].Detune); 130 | setRateScaling(-1,i,inst.ops[i].Rate_Scaling); 131 | //setAmplitudeModulation(-1,i,inst.ops[i].Attack_Rate); 132 | setSSG_EG(-1,i,inst.ops[i].SSG_EG); 133 | } 134 | } 135 | } 136 | i++; 137 | } 138 | entry.close(); 139 | } 140 | 141 | root.close(); 142 | 143 | } 144 | 145 | 146 | void YM2612::setDefaults() { 147 | 148 | unison = true; 149 | selected_channel = 1; 150 | operators[0] = true; 151 | operators[1] = true; 152 | operators[2] = true; 153 | operators[3] = true; 154 | 155 | for(int i=0;i<6;i++){ 156 | voices[i].on = false; 157 | keyOff(i); 158 | } 159 | 160 | //channel params 161 | setFeedback(0); 162 | setAlgorithm(7); 163 | setStereo(3); 164 | setAMS(0); 165 | setFMS(7); 166 | //operator params 167 | setAmplitudeModulation(1); 168 | setAttackRate(31); 169 | setDecayRate(31); 170 | setSustainRate(0); 171 | setReleaseRate(8); 172 | setTotalLevel(0); 173 | setSustainLevel(0); 174 | setMultiply(2); 175 | setDetune(3); 176 | setPlaymode(POLY6x1); 177 | 178 | } 179 | 180 | void YM2612::setLFO (int value) { 181 | //mod wheel value (0..8) is used both to enable 182 | // and to set lfo freq 183 | if(value==0){ 184 | setMasterParameter( YM_MA_LFO_E, 0); 185 | }else{ 186 | setMasterParameter( YM_MA_LFO_E, 1); 187 | setMasterParameter( YM_MA_LFO_F, value-1); 188 | } 189 | } 190 | 191 | void YM2612::sendData(uint8_t data) { 192 | digitalWrite(cs_pin, LOW); 193 | 194 | // take the latchPin low so data don't change while you're sending in bits: 195 | digitalWrite(latch_pin, LOW); 196 | // shift out the bits: 197 | shiftOut(data_pin, clock_pin, LSBFIRST, data); 198 | //take the latch pin high: 199 | digitalWrite(latch_pin, HIGH); 200 | 201 | delayMicroseconds(2); //it was 1 before 202 | digitalWrite(wr_pin, LOW); 203 | delayMicroseconds(5); 204 | digitalWrite(wr_pin, HIGH); 205 | delayMicroseconds(5); 206 | digitalWrite(cs_pin, HIGH); 207 | } 208 | 209 | 210 | void YM2612::setRegister(uint8_t part, uint8_t reg, uint8_t data) { 211 | digitalWrite(a1_pin, part); 212 | digitalWrite(a0_pin, LOW); 213 | sendData(reg); 214 | digitalWrite(a0_pin, HIGH); 215 | sendData(data); 216 | } 217 | 218 | void YM2612::setMasterParameter(int reg_offset, int val_size, int val_shift, int val) { 219 | uint8_t* p = (uint8_t *) ( &master) + reg_offset; 220 | 221 | *(p) &= ~(mask(val_size) << val_shift); //clean 222 | *(p) |= ((mask(val_size) & val) << val_shift); //write 223 | setRegister(0, YM_MASTER_ADDR + reg_offset, *(p)); 224 | 225 | } 226 | 227 | void YM2612::setChannelParameter(int chan, int reg_offset, int val_size, int val_shift, int val) { 228 | 229 | for (int c = 0; c < 6; c++){ 230 | if ( (unison && chan==-1 ) || (selected_channel==c && chan==-1 ) || (chan==c) ) { 231 | int channel_part = c / 3; 232 | uint8_t* p = (uint8_t *) ( &channels[channel_part]) + reg_offset; 233 | int channel_offset = c % 3; //which of the 12 registers 234 | 235 | *(p + channel_offset) &= ~(mask(val_size) << val_shift); //clean 236 | *(p + channel_offset) |= ((mask(val_size) & val) << val_shift); //write 237 | setRegister(channel_part, YM_CHN_ADDR + reg_offset + channel_offset, *(p + channel_offset)); 238 | } 239 | } 240 | 241 | } 242 | 243 | void YM2612::setOperatorParameter(int chan,int oper, int reg_offset, int val_size, int val_shift, int val) { 244 | for (int c = 0; c < 6; c++){ 245 | if ( (unison && chan==-1 ) || (selected_channel==c && chan==-1 ) || (chan==c) ) { 246 | for (int o = 0; o < 4; o++){ 247 | if ( (oper==-1 && operators[o] ) || (oper==o) ) { 248 | int channel_part = c / 3; 249 | uint8_t* p = (uint8_t *) ( &channels[channel_part]) + reg_offset; 250 | int op_offset = c % 3 + o * 4; //which of the 12 registers 251 | *(p + op_offset) &= ~(mask(val_size) << val_shift); //clean 252 | *(p + op_offset) |= ((mask(val_size) & val) << val_shift); //write 253 | setRegister(channel_part, YM_CHN_ADDR + reg_offset + op_offset, *(p + op_offset)); 254 | } 255 | } 256 | } 257 | } 258 | } 259 | 260 | 261 | 262 | 263 | void YM2612::setPlaymode(int value) { 264 | playmode = (playmode_t)value; 265 | 266 | // kill all voices 267 | for(int i = 0; i<6;i++){ 268 | voices[i].on = false; 269 | keyOff(i); 270 | } 271 | notes_stack0.clear(); 272 | notes_stack1.clear(); 273 | 274 | } 275 | 276 | void YM2612::noteOn(byte channel, byte pitch, byte velocity) 277 | { 278 | UNUSED(channel); 279 | UNUSED(velocity); 280 | 281 | 282 | switch(playmode) { 283 | 284 | case MONO1x6: 285 | { 286 | notes_stack0.add(pitch); 287 | for(int i=0;i<6;i++){ 288 | voices[i].on = true; 289 | voices[i].note = pitch; 290 | setNote(i,pitch); 291 | if(notes_stack0.size()==1) //trigger on first note only 292 | keyOn(i); 293 | } 294 | 295 | break; 296 | } 297 | case POLY6x1: 298 | { 299 | int index = -1; 300 | 301 | //attempts to find a free voice 302 | for(int i=0;i<6;i++) 303 | if(!voices[i].on){ 304 | index = i; 305 | voices_order[voices_order_index] = i; 306 | break; 307 | } 308 | 309 | // no free voice, just kill the oldest 310 | if(index==-1) 311 | index = voices_order[voices_order_index]; 312 | 313 | voices_order_index++; 314 | voices_order_index %=6; 315 | 316 | voices[index].on = true; 317 | voices[index].note = pitch; 318 | setNote(index,pitch); 319 | keyOn(index); 320 | break; 321 | } 322 | 323 | case POLY3x2: 324 | { 325 | int index = -1; 326 | int concurrent_voices = 2; 327 | 328 | //attempts to find a free voice 329 | for(int i=0;i<6;i+=concurrent_voices) 330 | if(!voices[i].on){ 331 | index = i; 332 | voices_order[voices_order_index] = i; 333 | break; 334 | } 335 | 336 | // no free voice, just kill the oldest 337 | if(index==-1) 338 | index = voices_order[voices_order_index]; 339 | 340 | voices_order_index+=concurrent_voices; 341 | voices_order_index %=6; 342 | 343 | for(int i=0;i0){ 431 | if( pitch == notes_stack0.get(notes_stack0.size()-1)){ 432 | notes_stack0.pop(); 433 | if(notes_stack0.size()>0){ 434 | uint8_t previous = notes_stack0.get(notes_stack0.size()-1); 435 | for(int i=0;i<6;i++){ 436 | voices[i].note = previous; 437 | setNote(i,previous); 438 | // dont trigger key on 439 | } 440 | } 441 | }else{ 442 | // do nothing 443 | // only remove note from the stack 444 | for(int n = 0;n= 2048) { 565 | frequency /= 2; 566 | block++; 567 | } 568 | freq = (uint16_t)frequency; 569 | 570 | //setMasterParameter( YM_MA_OP_CHAN, 0xF0 + ((channel/3) * 4 + channel%3 ) ); 571 | 572 | setRegister(chan/3, 0xA4+(chan%3), ((freq >> 8) & mask(3)) | ( ( block & mask(3) ) << 3) ); // Set frequency 573 | setRegister(chan/3, 0xA0+(chan%3), freq); 574 | 575 | } 576 | 577 | 578 | 579 | void YM2612::keyOn(uint8_t chan) { 580 | setMasterParameter( YM_MA_OP_CHAN, 0xF0 + ((chan/3) * 4 + chan%3 ) ); 581 | } 582 | 583 | void YM2612::keyOff(uint8_t chan) { 584 | setMasterParameter( YM_MA_OP_CHAN, 0x00 +((chan/3) * 4 + chan%3 ) ); 585 | } 586 | 587 | void YM2612::update(){ 588 | } 589 | 590 | -------------------------------------------------------------------------------- /ym2612_vgi/YM2612.h: -------------------------------------------------------------------------------- 1 | #ifndef YM2612_h 2 | #define YM2612_h 3 | 4 | #include "Arduino.h" 5 | #include 6 | #include "LinkedList.h" 7 | #include "VGI.h" 8 | #include 9 | #include 10 | 11 | #define UNUSED(x) (void)(x) 12 | #define YM_MASTER_ADDR (0x22) 13 | #define YM_CHN_ADDR (0x30) 14 | 15 | #define YM_MA_LFO_E offsetof(Master_t,LFO), 1, 3 16 | #define YM_MA_LFO_F offsetof(Master_t,LFO), 3, 0 17 | #define YM_MA_CH3_M offsetof(Master_t,CHAN3_MODE_TIMERS), 2, 6 18 | #define YM_MA_OP_CHAN offsetof(Master_t,OP_CHAN), 8, 0 19 | 20 | #define YM_OP_DT1 offsetof(Channels_t,DT1_MUL), 3, 4 21 | #define YM_OP_MUL offsetof(Channels_t,DT1_MUL), 4, 0 22 | #define YM_OP_TL offsetof(Channels_t,TL), 7, 0 23 | #define YM_OP_RS offsetof(Channels_t,RS_AR), 2, 6 24 | #define YM_OP_AR offsetof(Channels_t,RS_AR), 5, 0 25 | #define YM_OP_AM offsetof(Channels_t,AM_D1R), 1, 7 26 | #define YM_OP_D1R offsetof(Channels_t,AM_D1R), 5, 0 27 | #define YM_OP_D2R offsetof(Channels_t,D2R), 5, 0 28 | #define YM_OP_D1L offsetof(Channels_t,D1L_RR), 4, 4 29 | #define YM_OP_RR offsetof(Channels_t,D1L_RR), 4, 0 30 | #define YM_OP_SSG_EG offsetof(Channels_t,SSG_EG), 8, 0 31 | 32 | #define YM_CH_FB offsetof(Channels_t,FB_ALG), 3, 3 33 | #define YM_CH_ALG offsetof(Channels_t,FB_ALG), 3, 0 34 | #define YM_CH_L_R offsetof(Channels_t,L_R_AMS_FMS), 2, 6 35 | #define YM_CH_AMS offsetof(Channels_t,L_R_AMS_FMS), 2, 4 36 | #define YM_CH_FMS offsetof(Channels_t,L_R_AMS_FMS), 3, 0 37 | 38 | #define mask(s) (~(~0<0);} 107 | void selectOperator(int op, int value) {operators[op] = (value>0);} 108 | 109 | void loadPatch (); 110 | void selectPatch (int value) { patch_index = value;} 111 | 112 | 113 | //master params 114 | void setLFO (int value); 115 | void setChan3Mode (int value) { setMasterParameter( YM_MA_CH3_M, value);} 116 | 117 | 118 | 119 | //channel params 120 | void setFeedback (int chan, int value) { setChannelParameter( chan, YM_CH_FB, value);} 121 | void setAlgorithm (int chan, int value) { setChannelParameter( chan, YM_CH_ALG, value);} 122 | void setStereo (int chan, int value) { setChannelParameter( chan, YM_CH_L_R, value);} 123 | void setStereo (int chan, int l, int r) { setStereo(chan, (l<<1)|r);} 124 | void setAMS (int chan, int value) { setChannelParameter( chan, YM_CH_AMS, value);} 125 | void setFMS (int chan, int value) { setChannelParameter( chan, YM_CH_FMS, value);} 126 | //operator params 127 | void setAmplitudeModulation (int chan, int oper, int value) { setOperatorParameter( chan, oper, YM_OP_AM, (value>0));} 128 | void setAttackRate (int chan, int oper, int value) { setOperatorParameter( chan, oper, YM_OP_AR, value);} 129 | void setDecayRate (int chan, int oper, int value) { setOperatorParameter( chan, oper, YM_OP_D1R, value);} 130 | void setSustainRate (int chan, int oper, int value) { setOperatorParameter( chan, oper, YM_OP_D2R, value);} 131 | void setReleaseRate (int chan, int oper, int value) { setOperatorParameter( chan, oper, YM_OP_RR, value);} 132 | void setTotalLevel (int chan, int oper, int value) { setOperatorParameter( chan, oper, YM_OP_TL, value);} 133 | void setSustainLevel (int chan, int oper, int value) { setOperatorParameter( chan, oper, YM_OP_D1L, value);} 134 | void setMultiply (int chan, int oper, int value) { setOperatorParameter( chan, oper, YM_OP_MUL, value);} 135 | void setDetune (int chan, int oper, int value) { setOperatorParameter( chan, oper, YM_OP_DT1, value);} 136 | void setRateScaling (int chan, int oper, int value) { setOperatorParameter( chan, oper, YM_OP_RS, value);} 137 | void setSSG_EG (int chan, int oper, int value) { setOperatorParameter( chan, oper, YM_OP_SSG_EG, value);} 138 | //shortcuts 139 | void setFeedback (int value) { setFeedback(-1, value);} 140 | void setAlgorithm (int value) { setAlgorithm(-1, value);} 141 | void setStereo (int value) { setStereo(-1, value);} 142 | void setAMS (int value) { setAMS( -1, value);} 143 | void setFMS (int value) { setFMS(-1, value);} 144 | void setAmplitudeModulation (int value) { setAmplitudeModulation( -1, -1, value);} 145 | void setAttackRate (int value) { setAttackRate( -1, -1, value);} 146 | void setDecayRate (int value) { setDecayRate( -1, -1, value);} 147 | void setSustainRate (int value) { setSustainRate( -1, -1, value);} 148 | void setReleaseRate (int value) { setReleaseRate( -1, -1, value);} 149 | void setTotalLevel (int value) { setTotalLevel( -1, -1, value);} 150 | void setSustainLevel (int value) { setSustainLevel( -1, -1, value);} 151 | void setMultiply (int value) { setMultiply( -1, -1, value);} 152 | void setDetune (int value) { setDetune( -1, -1, value);} 153 | void setRateScaling (int value) { setRateScaling( -1, -1, value);} 154 | void setSSG_EG (int value) { setSSG_EG( -1, -1, value);} 155 | 156 | 157 | void noteOn(byte chan, byte pitch, byte velocity); 158 | void noteOff(byte chan, byte pitch, byte velocity); 159 | void pitchBend(byte channel, int bend); 160 | void update(); 161 | 162 | private: 163 | voice_t voices[6]; 164 | uint8_t voices_order[6]; 165 | uint8_t voices_order_index = 0; 166 | 167 | 168 | LinkedList notes_stack0 = LinkedList(); 169 | LinkedList voices_stack0 = LinkedList(); 170 | LinkedList notes_stack1 = LinkedList(); 171 | LinkedList voices_stack1 = LinkedList(); 172 | uint8_t splitNote = 60; 173 | int pitchBendValue = 0; 174 | 175 | playmode_t playmode; 176 | uint8_t selected_channel; 177 | bool operators[4]; 178 | bool unison; 179 | Master_t master; 180 | Channels_t channels[2]; 181 | uint8_t ic_pin; 182 | uint8_t cs_pin; 183 | uint8_t wr_pin; 184 | uint8_t rd_pin; 185 | uint8_t a0_pin; 186 | uint8_t a1_pin; 187 | uint8_t mc_pin; 188 | uint8_t latch_pin; 189 | uint8_t clock_pin; 190 | uint8_t data_pin; 191 | uint8_t sd_cs_pin; 192 | uint8_t patch_index = 0; 193 | uint8_t channelPart(); 194 | uint8_t channelOffset(); 195 | void sendData(uint8_t data); 196 | void setRegister(uint8_t part, uint8_t reg, uint8_t data); 197 | void setMasterParameter(int reg_offset, int val_size, int val_shift,int val); 198 | void setChannelParameter(int chan,int reg_offset, int val_size, int val_shift,int val); 199 | void setOperatorParameter(int chan,int oper, int reg_offset, int val_size, int val_shift, int val); 200 | 201 | void setDefaults(); 202 | void setNote(uint8_t channel, uint8_t note); 203 | void setFrequency(uint8_t channel, float frequency); 204 | void setSupplementaryFrequency(uint8_t channel, uint8_t oper, float frequency); 205 | void keyOn(uint8_t channel); 206 | void keyOff(uint8_t channel); 207 | 208 | 209 | static float noteToFrequency(uint8_t note); 210 | 211 | 212 | }; 213 | 214 | 215 | #endif 216 | 217 | 218 | 219 | 220 | /* 221 | 222 | from http://www.smspower.org/maxim/Documents/YM2612#reg27 223 | 224 | Part I memory map 225 | ================= 226 | 227 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 228 | | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | | 229 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 230 | | 22H | | | | | LFO enable | LFO frequency | | | 231 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 232 | | 24H | Timer A MSBs | | | | | | | | 233 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 234 | | 25H | | | | | | | Timer A LSBs | | 235 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 236 | | 26H | Timer B | | | | | | | | 237 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 238 | | 27H | Ch3 mode | | Reset B | Reset A | Enable B | Enable A | Load B | Load A | 239 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 240 | | 28H | Operator | | | | | Channel | | | 241 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 242 | | 29H | | | | | | | | | 243 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 244 | | 2AH | DAC | | | | | | | | 245 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 246 | | 2BH | DAC en | | | | | | | | 247 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 248 | | | | | | | | | | | 249 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 250 | | 30H+ | | DT1 | | | MUL | | | | 251 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 252 | | 40H+ | | TL | | | | | | | 253 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 254 | | 50H+ | RS | | | AR | | | | | 255 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 256 | | 60H+ | AM | | | D1R | | | | | 257 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 258 | | 70H+ | | | | D2R | | | | | 259 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 260 | | 80H+ | D1L | | | | RR | | | | 261 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 262 | | 90H+ | | | | | SSG-EG | | | | 263 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 264 | | | | | | | | | | | 265 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 266 | | A0H+ | Frequency number LSB | | | | | | | | 267 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 268 | | A4H+ | | | Block | | | Frequency Number MSB | | | 269 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 270 | | A8H+ | Ch3 supplementary frequency number | | | | | | | | 271 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 272 | | ACH+ | | | Ch3 supplementary block | | | Ch3 supplementary frequency number | | | 273 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 274 | | B0H+ | | | Feedback | | | Algorithm | | | 275 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 276 | | B4H+ | L | R | AMS | | | FMS | | | 277 | +------+------------------------------------+-----+-------------------------+---------+------------+------------------------------------+--------------+--------+ 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | MIDI Note Number to Frequency Conversion Chart 288 | ============================================== 289 | 290 | Note Frequency Note Frequency Note Frequency 291 | C1 0 8.1757989156 12 16.3515978313 24 32.7031956626 292 | Db 1 8.6619572180 13 17.3239144361 25 34.6478288721 293 | D 2 9.1770239974 14 18.3540479948 26 36.7080959897 294 | Eb 3 9.7227182413 15 19.4454364826 27 38.8908729653 295 | E 4 10.3008611535 16 20.6017223071 28 41.2034446141 296 | F 5 10.9133822323 17 21.8267644646 29 43.6535289291 297 | Gb 6 11.5623257097 18 23.1246514195 30 46.2493028390 298 | G 7 12.2498573744 19 24.4997147489 31 48.9994294977 299 | Ab 8 12.9782717994 20 25.9565435987 32 51.9130871975 300 | A 9 13.7500000000 21 27.5000000000 33 55.0000000000 301 | Bb 10 14.5676175474 22 29.1352350949 34 58.2704701898 302 | B 11 15.4338531643 23 30.8677063285 35 61.7354126570 303 | 304 | C4 36 65.4063913251 48 130.8127826503 60 261.6255653006 305 | Db 37 69.2956577442 49 138.5913154884 61 277.1826309769 306 | D 38 73.4161919794 50 146.8323839587 62 293.6647679174 307 | Eb 39 77.7817459305 51 155.5634918610 63 311.1269837221 308 | E 40 82.4068892282 52 164.8137784564 64 329.6275569129 309 | F 41 87.3070578583 53 174.6141157165 65 349.2282314330 310 | Gb 42 92.4986056779 54 184.9972113558 66 369.9944227116 311 | G 43 97.9988589954 55 195.9977179909 67 391.9954359817 312 | Ab 44 103.8261743950 56 207.6523487900 68 415.3046975799 313 | A 45 110.0000000000 57 220.0000000000 69 440.0000000000 314 | Bb 46 116.5409403795 58 233.0818807590 70 466.1637615181 315 | B 47 123.4708253140 59 246.9416506281 71 493.8833012561 316 | 317 | C7 72 523.2511306012 84 1046.5022612024 96 2093.0045224048 318 | Db 73 554.3652619537 85 1108.7305239075 97 2217.4610478150 319 | D 74 587.3295358348 86 1174.6590716696 98 2349.3181433393 320 | Eb 75 622.2539674442 87 1244.5079348883 99 2489.0158697766 321 | E 76 659.2551138257 88 1318.5102276515 100 2637.0204553030 322 | F 77 698.4564628660 89 1396.9129257320 101 2793.8258514640 323 | Gb 78 739.9888454233 90 1479.9776908465 102 2959.9553816931 324 | G 79 783.9908719635 91 1567.9817439270 103 3135.9634878540 325 | Ab 80 830.6093951599 92 1661.2187903198 104 3322.4375806396 326 | A 81 880.0000000000 93 1760.0000000000 105 3520.0000000000 327 | Bb 82 932.3275230362 94 1864.6550460724 106 3729.3100921447 328 | B 83 987.7666025122 95 1975.5332050245 107 3951.0664100490 329 | 330 | C10 108 4186.0090448096 120 8372.0180896192 331 | Db 109 4434.9220956300 121 8869.8441912599 332 | D 110 4698.6362866785 122 9397.2725733570 333 | Eb 111 4978.0317395533 123 9956.0634791066 334 | E 112 5274.0409106059 124 10548.0818212118 335 | F 113 5587.6517029281 125 11175.3034058561 336 | Gb 114 5919.9107633862 126 11839.8215267723 337 | G 115 6271.9269757080 127 12543.8539514160 338 | Ab 116 6644.8751612791 339 | A 117 7040.0000000000 340 | Bb 118 7458.6201842894 341 | B 119 7902.1328200980 342 | 343 | 344 | NOTES: Middle C is note #60. Frequency is in Hertz. 345 | 346 | Here is C code to calculate an array with all of the above frequencies (ie, so that midi[0], which is midi note #0, is assigned the value of 8.1757989156). Tuning is based upon A=440. 347 | 348 | float midi[127]; 349 | int a = 440; // a is 440 hz... 350 | for (int x = 0; x < 127; ++x) 351 | { 352 | midi[x] = (a / 32) * (2 ^ ((x - 9) / 12)); 353 | } 354 | 355 | 356 | 357 | */ 358 | -------------------------------------------------------------------------------- /ym2612_vgi/ym2612.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "YM2612.h" 3 | 4 | MIDI_CREATE_DEFAULT_INSTANCE(); 5 | 6 | YM2612 ym; 7 | bool play_seq = false; 8 | uint32_t interval = 300; 9 | 10 | void handleNoteOn(byte channel, byte pitch, byte velocity) 11 | { 12 | ym.noteOn(channel, pitch, velocity); 13 | } 14 | 15 | void handleNoteOff(byte channel, byte pitch, byte velocity) 16 | { 17 | ym.noteOff(channel, pitch, velocity); 18 | } 19 | 20 | 21 | void handlePitchBend(byte channel, int bend) 22 | { 23 | ym.pitchBend(channel, bend); 24 | } 25 | 26 | 27 | void handleControlChange(byte channel, byte number, byte value) 28 | { 29 | 30 | UNUSED(channel); 31 | 32 | switch(number) { 33 | 34 | // mod wheel 35 | case 1: 36 | ym.setLFO(value); 37 | break; 38 | 39 | // encoders 40 | case 21: 41 | ym.setPlaymode(value); 42 | break; 43 | case 22: 44 | //ym.setAttackRate(value); 45 | break; 46 | case 23: 47 | //ym.setAttackRate(value); 48 | break; 49 | case 24: 50 | ym.setFeedback(value); 51 | //interval = 10 * value; 52 | break; 53 | case 25: 54 | ym.selectPatch(value); 55 | break; 56 | case 26: 57 | ym.setStereo(value); 58 | break; 59 | case 27: 60 | ym.setAMS(value); 61 | break; 62 | case 28: 63 | ym.setFMS(value); 64 | break; 65 | 66 | // faders 67 | case 41: 68 | ym.setAttackRate(value); 69 | break; 70 | case 42: 71 | ym.setDecayRate(value); 72 | break; 73 | case 43: 74 | ym.setSustainRate(value); 75 | break; 76 | case 44: 77 | ym.setReleaseRate(value); 78 | break; 79 | case 45: 80 | ym.setTotalLevel(value); 81 | break; 82 | case 46: 83 | ym.setSustainLevel(value); 84 | break; 85 | case 47: 86 | ym.setMultiply(value); 87 | break; 88 | case 48: 89 | ym.setDetune(value); 90 | break; 91 | case 49: 92 | ym.setRateScaling(value); 93 | break; 94 | 95 | // toggles 96 | case 51: 97 | ym.selectOperator(0,value); 98 | break; 99 | case 52: 100 | ym.selectOperator(1,value); 101 | break; 102 | case 53: 103 | ym.selectOperator(2,value); 104 | break; 105 | case 54: 106 | ym.selectOperator(3,value); 107 | break; 108 | case 55: 109 | ym.setAlgorithm(value); 110 | break; 111 | case 56: 112 | ym.selectChannel(value); 113 | break; 114 | case 57: 115 | ym.setUnison(value); 116 | break; 117 | case 58: 118 | ym.setAmplitudeModulation(value); 119 | break; 120 | 121 | // transport 122 | case 112: 123 | break; 124 | case 113: 125 | break; 126 | case 114: 127 | play_seq = false; 128 | break; 129 | case 115: 130 | play_seq = true; 131 | break; 132 | case 116: 133 | ym.loadPatch(); 134 | break; 135 | case 117: 136 | break; 137 | 138 | } 139 | 140 | } 141 | 142 | 143 | 144 | void setup() { 145 | ym.setup(A5,A4,A3,A2,A1,A0,9, 6,7,5,4); 146 | ym.initialize(); 147 | 148 | digitalWrite(0, HIGH); // pullup for normal logic! 149 | 150 | MIDI.setHandleNoteOn(handleNoteOn); 151 | MIDI.setHandleNoteOff(handleNoteOff); 152 | MIDI.setHandleControlChange(handleControlChange); 153 | MIDI.setHandlePitchBend(handlePitchBend); 154 | 155 | 156 | MIDI.begin(MIDI_CHANNEL_OMNI); 157 | 158 | } 159 | 160 | 161 | 162 | void loop() { 163 | MIDI.read(); 164 | ym.update(); 165 | 166 | if(play_seq) 167 | playSeq(); 168 | 169 | } 170 | void playSeq(){ 171 | static uint8_t note = 0; 172 | static uint32_t previousMillis = 0; 173 | 174 | static bool pressed = false; 175 | uint32_t currentMillis = millis(); 176 | uint8_t basenote = 100; 177 | if (currentMillis - previousMillis >= interval) { 178 | previousMillis = currentMillis; 179 | if(pressed){ 180 | ym.noteOff(1, basenote+note, 0); 181 | note++; 182 | note %=12; 183 | pressed = false; 184 | }else{ 185 | ym.noteOn(1, basenote+note, 100); 186 | pressed = true; 187 | } 188 | 189 | } 190 | } 191 | --------------------------------------------------------------------------------