diff --git a/.gitignore b/.gitignore index 9afc324..35fe4ea 100644 --- a/.gitignore +++ b/.gitignore @@ -1,52 +1,52 @@ -# Ignore list for Eagle, a PCB layout tool - -# Backup files -*.s#? -*.b#? -*.l#? -*.b$? -*.s$? -*.l$? - -# Eagle project file -# It contains a serial number and references to the file structure -# on your computer. -# comment the following line if you want to have your project file included. -eagle.epf - -# Autorouter files -*.pro -*.job - -# CAM files -*.$$$ -*.cmp -*.ly2 -*.l15 -*.sol -*.plc -*.stc -*.sts -*.crc -*.crs - -*.dri -*.drl -*.gpi -*.pls -*.ger -*.gpi -*.xln - -*.drd -*.drd.* - -*.s#* -*.b#* - -*.info - -*.eps - -# file locks introduced since 7.x -*.lck +# Ignore list for Eagle, a PCB layout tool + +# Backup files +*.s#? +*.b#? +*.l#? +*.b$? +*.s$? +*.l$? + +# Eagle project file +# It contains a serial number and references to the file structure +# on your computer. +# comment the following line if you want to have your project file included. +eagle.epf + +# Autorouter files +*.pro +*.job + +# CAM files +*.$$$ +*.cmp +*.ly2 +*.l15 +*.sol +*.plc +*.stc +*.sts +*.crc +*.crs + +*.dri +*.drl +*.gpi +*.pls +*.ger +*.gpi +*.xln + +*.drd +*.drd.* + +*.s#* +*.b#* + +*.info + +*.eps + +# file locks introduced since 7.x +*.lck diff --git a/MIDI2CV.ino b/MIDI2CV.ino index e962b1c..1647d9d 100644 --- a/MIDI2CV.ino +++ b/MIDI2CV.ino @@ -1,593 +1,657 @@ -#include -#include -#include -#include - -#define MIDI_CHANNEL 1 - -#define OCTAVE_RANGE 10 -#define MAX_CV 10.0 -#define CV_PER_OCTAVE (MAX_CV / OCTAVE_RANGE) - -#define BASE_NOTE 21 -#define MAX_NOTE 108 -#define NOTE_RANGE MAX_NOTE - BASE_NOTE - -// Define Pitch Bend range to be a major second -#define BEND_RANGE ((CV_PER_OCTAVE / 12.0) * 1.5) - - -#define PIN_GATE_0 A5 -#define PIN_GATE_1 A1 -#define PIN_GATE_2 A2 -#define PIN_GATE_3 A3 - -#define ROTARY_SWITCH_PIN0 2 -#define ROTARY_SWITCH_PIN1 3 -#define ROTARY_SWITCH_PIN2 4 -#define ROTARY_SWITCH_PIN3 5 -#define ROTARY_SWITCH_PIN4 6 -#define ROTARY_SWITCH_PIN5 7 - -#define PIN_SPEED A4 - -#define PIN_FLIP_SWITCH_0 A6 -#define PIN_FLIP_SWITCH_1 A7 - -#define FLIP_SWITCH_UP 0 -#define FLIP_SWITCH_MIDDLE 1 -#define FLIP_SWITCH_DOWN 2 - - -#define MODE_MONO 0 -#define MODE_ARP 1 -#define MODE_SEQ 2 - - -#define MIDI_CLOCK_THRESHOLD_MILLIS 500 - -#define MIDI_CLOCK_DIVIDE_QUARTER 24 -#define MIDI_CLOCK_DIVIDE_HALF MIDI_CLOCK_DIVIDE_QUARTER * 2 -#define MIDI_CLOCK_DIVIDE_WHOLE MIDI_CLOCK_DIVIDE_HALF * 2 -#define MIDI_CLOCK_DIVIDE_EIGTH MIDI_CLOCK_DIVIDE_QUARTER / 2 -#define MIDI_CLOCK_DIVIDE_EIGHT_T MIDI_CLOCK_DIVIDE_QUARTER / 3 -#define MIDI_CLOCK_DIVIDE_SIXTEENTH MIDI_CLOCK_DIVIDE_EIGTH / 2 -#define MIDI_CLOCK_DIVIDE_SIXTEENTH_T MIDI_CLOCK_DIVIDE_EIGTH / 3 -#define MIDI_CLOCK_DIVIDE_THIRTY_SECOND MIDI_CLOCK_DIVIDE_SIXTEENTH / 2 -#define MIDI_CLOCK_DIVIDE_THIRTY_SECOND_T MIDI_CLOCK_DIVIDE_SIXTEENTH / 3 - -#define MIDI_CLOCK_DIVISION_COUNT 9 -const int clockDivisions[] = { MIDI_CLOCK_DIVIDE_WHOLE, MIDI_CLOCK_DIVIDE_HALF, - MIDI_CLOCK_DIVIDE_QUARTER, - MIDI_CLOCK_DIVIDE_EIGTH, MIDI_CLOCK_DIVIDE_EIGHT_T, - MIDI_CLOCK_DIVIDE_SIXTEENTH, MIDI_CLOCK_DIVIDE_SIXTEENTH_T, - MIDI_CLOCK_DIVIDE_THIRTY_SECOND, MIDI_CLOCK_DIVIDE_THIRTY_SECOND_T - }; - -#define MANUAL_CLOCK_MIN 20 -#define MANUAL_CLOCK_MAX 2000 - -#define SEQUENCE_COUNT 6 -#define SEQUENCE_LENGTH_MAX 128 - -#define ARP_DIRECTION_UP 0 -#define ARP_DIRECTION_DOWN 1 -#define ARP_DIRECTION_BOTH 2 -#define ARP_DIRECTION_ORDER 3 -#define ARP_DIRECTION_RANDOM 4 -#define ARP_DIRECTION_NONE 5 - -#define ARP_MODE_LATCH FLIP_SWITCH_UP -#define ARP_MODE_FORGET FLIP_SWITCH_MIDDLE -#define ARP_MODE_ADD FLIP_SWITCH_DOWN - - -DAC57X4 dac(4, 2, SS); - -MIDI_CREATE_DEFAULT_INSTANCE(); - -byte currentMode = MODE_MONO; - -byte flipSwitch0 = FLIP_SWITCH_UP; -byte flipSwitch1 = FLIP_SWITCH_UP; -byte rotarySwitch = 0; -int speedValue = 0; - - -float cv[] = {0, 0, 0, 0}; // 0 to MAX_CV -bool gate[] = {LOW, LOW, LOW, LOW}; // LOW or HIGH -bool midiStartSignal = LOW; -bool midiClockSignal = LOW; -unsigned long activeNotes[NOTE_RANGE]; -unsigned long noteCount = 1; -byte activeNoteCount = 0; -int currentPitchBend = 0; -byte currentModulation = 0; -byte currentVelocity = 0; -bool trigger = false; -bool released = false; - -byte lastChannel = 0; - -int clockCounter = 0; -unsigned long lastClockMillis = 0; -byte currentClockDivide = 0; -byte nextClockDivide = 0; - -unsigned long lastManualClockMillis = 0; - -byte currentSequencePosition = 0; - -byte currentArpPosition = 0; -unsigned long activeArpNotes[NOTE_RANGE]; -byte activeArpNoteCount = 0; -bool arpLatchReadyForNew = true; - -void setup() { - pinMode(PIN_GATE_0, OUTPUT); - pinMode(PIN_GATE_1, OUTPUT); - pinMode(PIN_GATE_2, OUTPUT); - pinMode(PIN_GATE_3, OUTPUT); - - MIDI.begin(MIDI_CHANNEL_OMNI); - MIDI.setHandleClock(onMidiClock); - MIDI.setHandleNoteOn(onMidiNoteOn); - MIDI.setHandleNoteOff(onMidiNoteOff); - MIDI.setHandleStart(onMidiStart); - MIDI.setHandleControlChange(onMidiControlChange); - MIDI.setHandlePitchBend(onMidiPitchBend); -} - -void onMidiClock() { - if(clockCounter == 0) { - midiClockSignal = HIGH; - } - clockCounter++; - if(clockCounter == clockDivisions[currentClockDivide]) { - clockCounter = 0; - currentClockDivide = nextClockDivide; - } - lastClockMillis = millis(); -} - -void onMidiNoteOn(byte channel, byte note, byte velocity) { - if(channel > MIDI_CHANNEL + 1) return; - if(note < BASE_NOTE || note > MAX_NOTE) return; - - lastChannel = channel; - - if(velocity == 0) { onMidiNoteOff(channel, note, velocity); return; } - - activeNotes[note - BASE_NOTE] = noteCount++; - activeNoteCount++; - currentVelocity = velocity; - trigger = true; -} - -void onMidiNoteOff(byte channel, byte note, byte velocity) { - if(channel > MIDI_CHANNEL + 1) return; - activeNotes[note - BASE_NOTE] = 0; - activeNoteCount--; - if(activeNoteCount == 0) currentVelocity = 0; - released = 0; -} - -void onMidiControlChange(byte channel, byte number, byte value) { - if(channel > MIDI_CHANNEL + 1) return; - currentModulation = value; -} - -void onMidiPitchBend(byte channel, int bend) { - if(channel > MIDI_CHANNEL + 1) return; - currentPitchBend = bend; -} - -void onMidiStart() { - midiStartSignal = HIGH; - clockCounter = 0; - currentClockDivide = nextClockDivide; -} - -float midiToCV(byte note) { - if(note < BASE_NOTE) return 0; - if(note - BASE_NOTE > NOTE_RANGE) return MAX_CV; - return mapfloat(note - BASE_NOTE, 0, 120.0, 0, MAX_CV); -} - -byte getMostRecentNote() { - byte note; - unsigned long maxTime = 0; - for(byte i = 0; i < NOTE_RANGE; i++) { - if(activeNotes[i] != 0 && activeNotes[i] >= maxTime) { - note = i; - maxTime = activeNotes[i]; - } - } - - return note; -} - -void loop() { - readSwitches(); - - if(flipSwitch0 == FLIP_SWITCH_UP) currentMode = MODE_MONO; - else if(flipSwitch0 == FLIP_SWITCH_MIDDLE) currentMode = MODE_SEQ; - else if(flipSwitch0 == FLIP_SWITCH_DOWN) currentMode = MODE_ARP; - - readSpeed(); - MIDI.read(); - - if(millis() - lastClockMillis > MIDI_CLOCK_THRESHOLD_MILLIS) { - // Apparently we are not getting any midi clocks, so we will just generate our own signal. - long waitTime = map(speedValue, 0, 1023, (60000) / MANUAL_CLOCK_MIN, (60000) / MANUAL_CLOCK_MAX); - if(millis() - lastManualClockMillis > waitTime) { - // Time for another clock signal! - lastManualClockMillis = millis(); - midiClockSignal = HIGH; - } - } else { - nextClockDivide = map(speedValue, 0, 1023, 0, MIDI_CLOCK_DIVISION_COUNT); - } - - bool triggerOut = false; - - - switch(currentMode) { - case MODE_MONO: - if(activeNoteCount > 0) { - // Find most recent hit key - byte note = getMostRecentNote(); - - float value = midiToCV(note + BASE_NOTE); - cv[0] = value + mapfloat(currentPitchBend, 0, MIDI_PITCHBEND_MAX, -BEND_RANGE, BEND_RANGE); - cv[1] = mapfloat(currentVelocity, 0, 127, 0, MAX_CV); - cv[2] = mapfloat(currentModulation, 0, 127, 0, MAX_CV); - triggerOut = trigger; - if(lastChannel == MIDI_CHANNEL + 1 && trigger) { // IF on second channel, we retrigger the gate. - gate[0] = LOW; - } else { - gate[0] = HIGH; - } - } else { - gate[0] = LOW; - } - break; - case MODE_SEQ: - if(flipSwitch1 == FLIP_SWITCH_UP) { - // Rec mode. - if(activeNoteCount > 0) { - // Find most recent hit key - byte note = getMostRecentNote(); - float value = midiToCV(note + BASE_NOTE); - cv[0] = value + mapfloat(currentPitchBend, 0, MIDI_PITCHBEND_MAX, -BEND_RANGE, BEND_RANGE); - gate[0] = HIGH; - if(trigger) { - triggerOut = true; - - EEPROM.update(rotarySwitch, EEPROM[rotarySwitch] + 1); - byte notePosition = EEPROM[rotarySwitch] - 1; - EEPROM.update(SEQUENCE_COUNT + rotarySwitch * SEQUENCE_LENGTH_MAX + notePosition, note); - } - } else { - gate[0] = LOW; - triggerOut = false; - } - } else if(flipSwitch1 == FLIP_SWITCH_MIDDLE) { - // Play Mode - if(activeNoteCount > 0 && EEPROM[rotarySwitch] > 0) { - byte note = getMostRecentNote(); - byte currentSequenceValue = EEPROM[SEQUENCE_COUNT + rotarySwitch * SEQUENCE_LENGTH_MAX + currentSequencePosition]; - note = currentSequenceValue + note - EEPROM[SEQUENCE_COUNT + rotarySwitch * SEQUENCE_LENGTH_MAX + 0]; - - if(trigger && millis() - lastClockMillis > MIDI_CLOCK_THRESHOLD_MILLIS) { - // no midi input but a key was pressed, so we start the sequence now instead of at next clock signal - midiClockSignal = HIGH; - lastManualClockMillis = millis(); - } - - if(midiClockSignal) { // trigger a new note! - triggerOut = true; - float value = midiToCV(note + BASE_NOTE); - cv[0] = value + mapfloat(currentPitchBend, 0, MIDI_PITCHBEND_MAX, -BEND_RANGE, BEND_RANGE); - currentSequencePosition = (currentSequencePosition + 1) % EEPROM[rotarySwitch]; - } - gate[0] = HIGH; - } else { - gate[0] = LOW; - currentSequencePosition = 0; - } - } else if(flipSwitch1 == FLIP_SWITCH_DOWN) { - // clear on note - if(activeNoteCount > 0 && trigger) { - EEPROM.update(rotarySwitch, 0); - } - } - break; - case MODE_ARP: - if(flipSwitch1 == ARP_MODE_LATCH) { - // ARP Mode LATCH - if(trigger) { - if(activeNoteCount == 1) { - // first note of the new arpeggio pressed - currentArpPosition = 0; - activeArpNoteCount = 1; - for(int i = 0; i < NOTE_RANGE; i++) { - if(activeNotes[i] != 0) currentArpPosition = i; // This is the first note of our arpeggio, so set it to this - activeArpNotes[i] = activeNotes[i]; - } - } else { - // new note for current arpeggio - for(int i = 0; i < NOTE_RANGE; i++) { - if(activeNotes[i] != 0 && activeArpNotes[i] == 0) activeArpNoteCount++; - if(activeNotes[i] != 0) // We don't want to disable any notes, only activate new ones - activeArpNotes[i] = activeNotes[i]; - } - } - } - } else if(flipSwitch1 == ARP_MODE_FORGET) { - // activeArpNotes is equivalent to activeNotes. ezpz - for(int i = 0; i < NOTE_RANGE; i++) { - activeArpNotes[i] = activeNotes[i]; - } - activeArpNoteCount = activeNoteCount; - if(released && activeNoteCount == 0) { - currentArpPosition = 0; - } - } else if(flipSwitch1 == ARP_MODE_ADD) { - // we just add any active Note until some mysterious signal tells us to reset (modulation > 63!) - if(currentModulation < 64) { - byte active = 0; - for(int i = 0; i < NOTE_RANGE; i++) { - if(activeNotes[i] > 0) { - activeArpNotes[i] = activeNotes[i]; - - } - if(activeArpNotes[i] != 0) - active++; - } - activeArpNoteCount = active; - } else { - activeArpNoteCount = 0; - for(int i = 0; i < NOTE_RANGE; i++) - activeArpNotes[i] = 0; - } - } - - - - if(activeArpNoteCount > 0) { - - if( activeArpNotes[currentArpPosition] == 0) { - // find the first note in the arp. - switch(rotarySwitch) { - case ARP_DIRECTION_UP: - case ARP_DIRECTION_BOTH: - for(int i = 0; i < NOTE_RANGE; i++) - if(activeArpNotes[i] != 0) { - currentArpPosition = i; - break; - } - break; - case ARP_DIRECTION_DOWN: - for(int i = NOTE_RANGE - 1; i >= 0; i--) - if(activeArpNotes[i] != 0) { - currentArpPosition = i; - break; - } - break; - case ARP_DIRECTION_RANDOM: - byte newIndex = 0; - - do { - newIndex = random(0, 255); - } while(activeArpNotes[newIndex] == 0 || currentArpPosition == newIndex); - - currentArpPosition = newIndex; - break; - case ARP_DIRECTION_ORDER: - byte minValue = 0; - byte minValueIndex = 0; - for(int i = 0; i < NOTE_RANGE; i++) { - if(i == currentArpPosition || activeArpNotes[i] == 0) continue; - if(activeArpNotes[i] < minValue) { - minValue = activeArpNotes[i]; - minValueIndex = i; - } - } - currentArpPosition = minValueIndex; - break; - } - } - - byte note = currentArpPosition; // This is the current Arp Note to play - - if(midiClockSignal) { // trigger a new note! - triggerOut = true; - float value = midiToCV(note + BASE_NOTE); - cv[0] = value + mapfloat(currentPitchBend, 0, MIDI_PITCHBEND_MAX, -BEND_RANGE, BEND_RANGE); - // now we have to find the next arp position. this depends on the current mode. - bool foundNote = false; - - switch(rotarySwitch) { - case ARP_DIRECTION_UP: - if(activeArpNoteCount == 1) break; - - // We just go up and if we reach the last note in the arp, we go back to the first one - for(int i = currentArpPosition + 1; i < NOTE_RANGE; i++) { - if(activeArpNotes[i] != 0) { - // found the next note! - currentArpPosition = i; - foundNote = true; - break; - } - } - - if(!foundNote) { - // We have to find the first note at the beginning of the arpeggio now... - for(int i = 0; i < NOTE_RANGE; i++) { - if(activeArpNotes[i] != 0) { - // found the next note! - currentArpPosition = i; - break; - } - } - } - - break; - case ARP_DIRECTION_DOWN: - if(activeArpNoteCount == 1) break; - // We just go down and if we reach the first note in the arp, we go forward to the last one - for(int i = currentArpPosition - 1; i >= 0; i--) { - if(activeArpNotes[i] != 0) { - // found the next note! - currentArpPosition = i; - foundNote = true; - break; - } - } - - if(!foundNote) { - // We have to find the last note at the beginning of the arpeggio now... - for(int i = NOTE_RANGE - 1; i >= 0; i--) { - if(activeArpNotes[i] != 0) { - // found the next note! - currentArpPosition = i; - break; - } - } - } - break; - case ARP_DIRECTION_BOTH: - if(activeArpNoteCount == 1) break; - // We just go up and if we reach the last note in the arp, we go back one note - for(int i = currentArpPosition + 1; i < NOTE_RANGE; i++) { - if(activeArpNotes[i] != 0) { - // found the next note! - currentArpPosition = i; - foundNote = true; - break; - } - } - // we are going downwards, so let's search! - if(!foundNote) { - for(int i = currentArpPosition - 1; i >= 0; i--) { - if(activeArpNotes[i] != 0) { - // found the next note! - currentArpPosition = i; - foundNote = true; - break; - } - } - } - - break; - case ARP_DIRECTION_ORDER: - if(activeArpNoteCount == 1) break; - // We find the note that has the least distance to the current notes value. - // If we can't find one, we assign the note with the lowest value - byte minValue = 255; - byte minValueIndex = 0; - for(int i = 0; i < NOTE_RANGE; i++) { - if(i == currentArpPosition || activeArpNotes[i] == 0) continue; - byte distance = abs(activeArpNotes[i] - activeArpNotes[currentArpPosition]); - if(distance < minValue) { - minValue = distance; - minValueIndex = i; - } - } - - if(minValue == 255) { // We did not find a higher note, so let's go back to the first one. - minValue = 0; - for(int i = 0; i < NOTE_RANGE; i++) { - if(i == currentArpPosition || activeArpNotes[i] == 0) continue; - if(activeArpNotes[i] < minValue) { - minValue = activeArpNotes[i]; - minValueIndex = i; - } - } - } - - currentArpPosition = minValueIndex; - break; - case ARP_DIRECTION_RANDOM: - byte newIndex = 0; - - do { - newIndex = random(0, 255); - } while(activeArpNotes[newIndex] == 0 || currentArpPosition == newIndex); - - currentArpPosition = newIndex; - - break; - case ARP_DIRECTION_NONE: - // Noone knows what happens here. - break; - } - - } - gate[0] = HIGH; - - - - - } else { - gate[0] = LOW; - currentArpPosition = 0; - } - - break; - } - - gate[1] = triggerOut ? HIGH : LOW; - gate[2] = midiStartSignal; - gate[3] = midiClockSignal; - - trigger = false; - released = false; - midiStartSignal = LOW; - midiClockSignal = LOW; - - writeDACs(); - writeGates(); -} - -float mapfloat(float x, float in_min, float in_max, float out_min, float out_max) -{ - return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; -} - -void readSwitches() { - int analogValue = analogRead(PIN_FLIP_SWITCH_0); - if(analogValue < 100) flipSwitch0 = FLIP_SWITCH_UP; - else if(analogValue < 900) flipSwitch0 = FLIP_SWITCH_DOWN; - else flipSwitch0 = FLIP_SWITCH_MIDDLE; - analogValue = analogRead(PIN_FLIP_SWITCH_1); - if(analogValue < 100) flipSwitch1 = FLIP_SWITCH_UP; - else if(analogValue < 900) flipSwitch1 = FLIP_SWITCH_DOWN; - else flipSwitch1 = FLIP_SWITCH_MIDDLE; - - if(digitalRead(ROTARY_SWITCH_PIN0) == LOW) rotarySwitch = 0; - else if(digitalRead(ROTARY_SWITCH_PIN1) == LOW) rotarySwitch = 1; - else if(digitalRead(ROTARY_SWITCH_PIN2) == LOW) rotarySwitch = 2; - else if(digitalRead(ROTARY_SWITCH_PIN3) == LOW) rotarySwitch = 3; - else if(digitalRead(ROTARY_SWITCH_PIN4) == LOW) rotarySwitch = 4; - else if(digitalRead(ROTARY_SWITCH_PIN5) == LOW) rotarySwitch = 5; -} - -void readSpeed() { - speedValue = analogRead(PIN_SPEED); -} - -void writeDACs() { - dac.SetDAC(cv[0], 1); - dac.SetDAC(cv[1], 2); - dac.SetDAC(cv[2], 3); - dac.SetDAC(cv[3], 4); -} - -void writeGates() { - digitalWrite(PIN_GATE_0, gate[0] == HIGH ? LOW : HIGH); - digitalWrite(PIN_GATE_1, gate[1] == HIGH ? LOW : HIGH); - digitalWrite(PIN_GATE_2, gate[2] == HIGH ? LOW : HIGH); - digitalWrite(PIN_GATE_3, gate[3] == HIGH ? LOW : HIGH); -} +#include +#include +#include +#include +#include +#include +#include + +#define MIDI_CHANNEL 1 + +#define OCTAVE_RANGE 10 +#define MAX_CV 10.0 +#define NOTES_PER_OCTAVE 12 +#define CV_PER_OCTAVE 1.0 +#define CV_PER_NOTE CV_PER_OCTAVE / NOTES_PER_OCTAVE + +#define BASE_NOTE 21 +#define MAX_NOTE 108 +#define NOTE_RANGE OCTAVE_RANGE * NOTES_PER_OCTAVE + +// Define Pitch Bend range to be a major second +#define BEND_RANGE ((CV_PER_NOTE) * 1) + +#define PIN_USB_RESET 7 + +#define PIN_GATE_0 A5 +#define PIN_GATE_1 A1 +#define PIN_GATE_2 A2 +#define PIN_GATE_3 A3 + +#define ROTARY_SWITCH_PIN0 2 +#define ROTARY_SWITCH_PIN1 3 +#define ROTARY_SWITCH_PIN2 4 + +#define PIN_SPEED A4 + +#define PIN_FLIP_SWITCH_0 A6 +#define PIN_FLIP_SWITCH_1 A7 + +#define FLIP_SWITCH_UP 0 +#define FLIP_SWITCH_MIDDLE 1 +#define FLIP_SWITCH_DOWN 2 + + +#define MODE_MONO 0 +#define MODE_ARP 1 +#define MODE_SEQ 2 + + +#define MIDI_CLOCK_THRESHOLD_MILLIS 500 + +#define MIDI_CLOCK_DIVIDE_QUARTER 24 +#define MIDI_CLOCK_DIVIDE_HALF MIDI_CLOCK_DIVIDE_QUARTER * 2 +#define MIDI_CLOCK_DIVIDE_WHOLE MIDI_CLOCK_DIVIDE_HALF * 2 +#define MIDI_CLOCK_DIVIDE_EIGTH MIDI_CLOCK_DIVIDE_QUARTER / 2 +#define MIDI_CLOCK_DIVIDE_EIGHT_T MIDI_CLOCK_DIVIDE_QUARTER / 3 +#define MIDI_CLOCK_DIVIDE_SIXTEENTH MIDI_CLOCK_DIVIDE_EIGTH / 2 +#define MIDI_CLOCK_DIVIDE_SIXTEENTH_T MIDI_CLOCK_DIVIDE_EIGTH / 3 +#define MIDI_CLOCK_DIVIDE_THIRTY_SECOND MIDI_CLOCK_DIVIDE_SIXTEENTH / 2 +#define MIDI_CLOCK_DIVIDE_THIRTY_SECOND_T MIDI_CLOCK_DIVIDE_SIXTEENTH / 3 + +#define MIDI_CLOCK_DIVISION_COUNT 9 +const int clockDivisions[] = { MIDI_CLOCK_DIVIDE_WHOLE, MIDI_CLOCK_DIVIDE_HALF, + MIDI_CLOCK_DIVIDE_QUARTER, + MIDI_CLOCK_DIVIDE_EIGTH, MIDI_CLOCK_DIVIDE_EIGHT_T, + MIDI_CLOCK_DIVIDE_SIXTEENTH, MIDI_CLOCK_DIVIDE_SIXTEENTH_T, + MIDI_CLOCK_DIVIDE_THIRTY_SECOND, MIDI_CLOCK_DIVIDE_THIRTY_SECOND_T + }; + +#define MANUAL_CLOCK_MIN 20 +#define MANUAL_CLOCK_MAX 2000 + +#define SEQUENCE_COUNT 6 +#define SEQUENCE_LENGTH_MAX 128 + +#define ARP_DIRECTION_UP 0 +#define ARP_DIRECTION_DOWN 1 +#define ARP_DIRECTION_BOTH 2 +#define ARP_DIRECTION_ORDER 3 +#define ARP_DIRECTION_RANDOM 4 +#define ARP_DIRECTION_NONE 5 + +#define ARP_MODE_LATCH FLIP_SWITCH_UP +#define ARP_MODE_FORGET FLIP_SWITCH_MIDDLE +#define ARP_MODE_ADD FLIP_SWITCH_DOWN + + +DAC57X4 dac(4, 2, SS); + + +class USBMidiParser +{ + public: + USBMidiParser(USBH_MIDI *usbThing); + int available(); + void begin(unsigned baud); + byte read(); + void write(unsigned char data); + private: + midi::RingBuffer rxBuffer; + USBH_MIDI *usb; +}; + +USBMidiParser::USBMidiParser(USBH_MIDI *usbThing) { + usb = usbThing; +} + +int USBMidiParser::available() { + uint8_t buf[20]; + byte length = 0; + if((length = usb->RecvData(buf)) > 0) { + for(byte i = 0; i < length; i++) + rxBuffer.write(buf[i]); + } + return rxBuffer.getLength(); +} + +void USBMidiParser::begin(unsigned baud) { + rxBuffer.clear(); +} + +byte USBMidiParser::read() { + return rxBuffer.read(); +} + +void USBMidiParser::write(unsigned char asd) {} + +USB Usb; +USBH_MIDI usbMidi(&Usb); +USBMidiParser parser(&usbMidi); +boolean usbMidiEnabled = false; + +MIDI_CREATE_DEFAULT_INSTANCE(); +MIDI_CREATE_INSTANCE(USBMidiParser, parser, MIDIUSB); + +byte currentMode = MODE_MONO; + +byte flipSwitch0 = FLIP_SWITCH_UP; +byte flipSwitch1 = FLIP_SWITCH_UP; +byte rotarySwitch = 0; +int speedValue = 0; + + +float cv[] = {0, 0, 0, 0}; // 0 to MAX_CV +bool gate[] = {LOW, LOW, LOW, LOW}; // LOW or HIGH +bool midiStartSignal = LOW; +bool midiClockSignal = LOW; +byte activeNotes[NOTE_RANGE]; +byte noteCount = 1; +byte activeNoteCount = 0; +int currentPitchBend = 0; +byte currentModulation = 0; +byte currentVelocity = 0; +bool trigger = false; +bool released = false; + +byte lastChannel = 0; + +int clockCounter = 0; +unsigned long lastClockMillis = 0; +byte currentClockDivide = 0; +byte nextClockDivide = 0; + +unsigned long lastManualClockMillis = 0; + +byte currentSequencePosition = 0; + +byte currentArpPosition = 0; +byte activeArpNotes[NOTE_RANGE]; +byte activeArpNoteCount = 0; +bool arpLatchReadyForNew = true; + +void setup() { + pinMode(PIN_GATE_0, OUTPUT); + pinMode(PIN_GATE_1, OUTPUT); + pinMode(PIN_GATE_2, OUTPUT); + pinMode(PIN_GATE_3, OUTPUT); + + MIDI.begin(MIDI_CHANNEL_OMNI); + MIDI.setHandleClock(onMidiClock); + MIDI.setHandleNoteOn(onMidiNoteOn); + MIDI.setHandleNoteOff(onMidiNoteOff); + MIDI.setHandleStart(onMidiStart); + MIDI.setHandleControlChange(onMidiControlChange); + MIDI.setHandlePitchBend(onMidiPitchBend); + + if(Usb.Init() == -1) { + usbMidiEnabled = false; + } else { + usbMidiEnabled = true; + + MIDIUSB.begin(MIDI_CHANNEL_OMNI); + MIDIUSB.setHandleClock(onMidiClock); + MIDIUSB.setHandleNoteOn(onMidiNoteOn); + MIDIUSB.setHandleNoteOff(onMidiNoteOff); + MIDIUSB.setHandleStart(onMidiStart); + MIDIUSB.setHandleControlChange(onMidiControlChange); + MIDIUSB.setHandlePitchBend(onMidiPitchBend); + } +} + +void onMidiClock() { + if(clockCounter == 0) { + midiClockSignal = HIGH; + } + clockCounter++; + if(clockCounter == clockDivisions[currentClockDivide]) { + clockCounter = 0; + currentClockDivide = nextClockDivide; + } + lastClockMillis = millis(); +} + +void onMidiNoteOn(byte channel, byte note, byte velocity) { + if(channel > MIDI_CHANNEL + 1) return; + if(note < BASE_NOTE || note > MAX_NOTE) return; + + lastChannel = channel; + + if(velocity == 0) { onMidiNoteOff(channel, note, velocity); return; } + + activeNotes[note - BASE_NOTE] = noteCount++; + activeNoteCount++; + currentVelocity = velocity; + trigger = true; +} + +void onMidiNoteOff(byte channel, byte note, byte velocity) { + if(channel > MIDI_CHANNEL + 1) return; + activeNotes[note - BASE_NOTE] = 0; + activeNoteCount--; + if(activeNoteCount == 0) { + currentVelocity = 0; + noteCount = 1; + } + released = 0; +} + +void onMidiControlChange(byte channel, byte number, byte value) { + if(channel > MIDI_CHANNEL + 1) return; + currentModulation = value; +} + +void onMidiPitchBend(byte channel, int bend) { + if(channel > MIDI_CHANNEL + 1) return; + currentPitchBend = bend; +} + +void onMidiStart() { + midiStartSignal = HIGH; + clockCounter = 0; + currentClockDivide = nextClockDivide; +} + +float midiToCV(byte note) { + if(note < BASE_NOTE) return 0; + if(note - BASE_NOTE > NOTE_RANGE) return MAX_CV; + return (note - BASE_NOTE) * CV_PER_NOTE; +} + +byte getMostRecentNote() { + byte note; + unsigned long maxTime = 0; + for(byte i = 0; i < NOTE_RANGE; i++) { + if(activeNotes[i] != 0 && activeNotes[i] >= maxTime) { + note = i; + maxTime = activeNotes[i]; + } + } + + return note; +} + +void loop() { + readSwitches(); + + if(flipSwitch0 == FLIP_SWITCH_UP) currentMode = MODE_MONO; + else if(flipSwitch0 == FLIP_SWITCH_MIDDLE) currentMode = MODE_SEQ; + else if(flipSwitch0 == FLIP_SWITCH_DOWN) currentMode = MODE_ARP; + + readSpeed(); + MIDI.read(); + if(usbMidiEnabled) { + Usb.Task(); + if(usbMidi) + MIDIUSB.read(); + } + + if(millis() - lastClockMillis > MIDI_CLOCK_THRESHOLD_MILLIS) { + // Apparently we are not getting any midi clocks, so we will just generate our own signal. + long waitTime = map(speedValue, 0, 1023, (60000) / MANUAL_CLOCK_MIN, (60000) / MANUAL_CLOCK_MAX); + if(millis() - lastManualClockMillis > waitTime) { + // Time for another clock signal! + lastManualClockMillis = millis(); + midiClockSignal = HIGH; + } + } else { + nextClockDivide = map(speedValue, 0, 1023, 0, MIDI_CLOCK_DIVISION_COUNT); + } + + bool triggerOut = false; + + + switch(currentMode) { + case MODE_MONO: + if(activeNoteCount > 0) { + // Find most recent hit key + byte note = getMostRecentNote(); + + float value = midiToCV(note + BASE_NOTE); + cv[0] = value + mapfloat(currentPitchBend, 0, MIDI_PITCHBEND_MAX, -BEND_RANGE, BEND_RANGE); + cv[1] = mapfloat(currentVelocity, 0, 127, 0, MAX_CV); + cv[2] = mapfloat(currentModulation, 0, 127, 0, MAX_CV); + triggerOut = trigger; + if(lastChannel == MIDI_CHANNEL + 1 && trigger) { // IF on second channel, we retrigger the gate. + gate[0] = LOW; + } else { + gate[0] = HIGH; + } + } else { + gate[0] = LOW; + } + break; + case MODE_SEQ: + if(flipSwitch1 == FLIP_SWITCH_UP) { + // Rec mode. + if(activeNoteCount > 0) { + // Find most recent hit key + byte note = getMostRecentNote(); + float value = midiToCV(note + BASE_NOTE); + cv[0] = value + mapfloat(currentPitchBend, 0, MIDI_PITCHBEND_MAX, -BEND_RANGE, BEND_RANGE); + gate[0] = HIGH; + if(trigger) { + triggerOut = true; + + EEPROM.update(rotarySwitch, EEPROM[rotarySwitch] + 1); + byte notePosition = EEPROM[rotarySwitch] - 1; + EEPROM.update(SEQUENCE_COUNT + rotarySwitch * SEQUENCE_LENGTH_MAX + notePosition, note); + } + } else { + gate[0] = LOW; + triggerOut = false; + } + } else if(flipSwitch1 == FLIP_SWITCH_MIDDLE) { + // Play Mode + if(activeNoteCount > 0 && EEPROM[rotarySwitch] > 0) { + byte note = getMostRecentNote(); + byte currentSequenceValue = EEPROM[SEQUENCE_COUNT + rotarySwitch * SEQUENCE_LENGTH_MAX + currentSequencePosition]; + note = currentSequenceValue + note - EEPROM[SEQUENCE_COUNT + rotarySwitch * SEQUENCE_LENGTH_MAX + 0]; + + if(trigger && millis() - lastClockMillis > MIDI_CLOCK_THRESHOLD_MILLIS) { + // no midi input but a key was pressed, so we start the sequence now instead of at next clock signal + midiClockSignal = HIGH; + lastManualClockMillis = millis(); + } + + if(midiClockSignal) { // trigger a new note! + triggerOut = true; + float value = midiToCV(note + BASE_NOTE); + cv[0] = value + mapfloat(currentPitchBend, 0, MIDI_PITCHBEND_MAX, -BEND_RANGE, BEND_RANGE); + currentSequencePosition = (currentSequencePosition + 1) % EEPROM[rotarySwitch]; + } + gate[0] = HIGH; + } else { + gate[0] = LOW; + currentSequencePosition = 0; + } + } else if(flipSwitch1 == FLIP_SWITCH_DOWN) { + // clear on note + if(activeNoteCount > 0 && trigger) { + EEPROM.update(rotarySwitch, 0); + } + } + break; + case MODE_ARP: + if(flipSwitch1 == ARP_MODE_LATCH) { + // ARP Mode LATCH + if(trigger) { + if(activeNoteCount == 1) { + // first note of the new arpeggio pressed + currentArpPosition = 0; + activeArpNoteCount = 1; + for(int i = 0; i < NOTE_RANGE; i++) { + if(activeNotes[i] != 0) currentArpPosition = i; // This is the first note of our arpeggio, so set it to this + activeArpNotes[i] = activeNotes[i]; + } + } else { + // new note for current arpeggio + for(int i = 0; i < NOTE_RANGE; i++) { + if(activeNotes[i] != 0 && activeArpNotes[i] == 0) activeArpNoteCount++; + if(activeNotes[i] != 0) // We don't want to disable any notes, only activate new ones + activeArpNotes[i] = activeNotes[i]; + } + } + } + } else if(flipSwitch1 == ARP_MODE_FORGET) { + // activeArpNotes is equivalent to activeNotes. ezpz + for(int i = 0; i < NOTE_RANGE; i++) { + activeArpNotes[i] = activeNotes[i]; + } + activeArpNoteCount = activeNoteCount; + if(released && activeNoteCount == 0) { + currentArpPosition = 0; + } + } else if(flipSwitch1 == ARP_MODE_ADD) { + // we just add any active Note until some mysterious signal tells us to reset (modulation > 63!) + if(currentModulation < 64) { + byte active = 0; + for(int i = 0; i < NOTE_RANGE; i++) { + if(activeNotes[i] > 0) { + activeArpNotes[i] = activeNotes[i]; + + } + if(activeArpNotes[i] != 0) + active++; + } + activeArpNoteCount = active; + } else { + activeArpNoteCount = 0; + for(int i = 0; i < NOTE_RANGE; i++) + activeArpNotes[i] = 0; + } + } + + + + if(activeArpNoteCount > 0) { + + if( activeArpNotes[currentArpPosition] == 0) { + // find the first note in the arp. + switch(rotarySwitch) { + case ARP_DIRECTION_UP: + case ARP_DIRECTION_BOTH: + for(int i = 0; i < NOTE_RANGE; i++) + if(activeArpNotes[i] != 0) { + currentArpPosition = i; + break; + } + break; + case ARP_DIRECTION_DOWN: + for(int i = NOTE_RANGE - 1; i >= 0; i--) + if(activeArpNotes[i] != 0) { + currentArpPosition = i; + break; + } + break; + case ARP_DIRECTION_RANDOM: + byte newIndex = 0; + + do { + newIndex = random(0, 255); + } while(activeArpNotes[newIndex] == 0 || currentArpPosition == newIndex); + + currentArpPosition = newIndex; + break; + case ARP_DIRECTION_ORDER: + byte minValue = 0; + byte minValueIndex = 0; + for(int i = 0; i < NOTE_RANGE; i++) { + if(i == currentArpPosition || activeArpNotes[i] == 0) continue; + if(activeArpNotes[i] < minValue) { + minValue = activeArpNotes[i]; + minValueIndex = i; + } + } + currentArpPosition = minValueIndex; + break; + } + } + + byte note = currentArpPosition; // This is the current Arp Note to play + + if(midiClockSignal) { // trigger a new note! + triggerOut = true; + float value = midiToCV(note + BASE_NOTE); + cv[0] = value + mapfloat(currentPitchBend, 0, MIDI_PITCHBEND_MAX, -BEND_RANGE, BEND_RANGE); + // now we have to find the next arp position. this depends on the current mode. + bool foundNote = false; + + switch(rotarySwitch) { + case ARP_DIRECTION_UP: + if(activeArpNoteCount == 1) break; + + // We just go up and if we reach the last note in the arp, we go back to the first one + for(int i = currentArpPosition + 1; i < NOTE_RANGE; i++) { + if(activeArpNotes[i] != 0) { + // found the next note! + currentArpPosition = i; + foundNote = true; + break; + } + } + + if(!foundNote) { + // We have to find the first note at the beginning of the arpeggio now... + for(int i = 0; i < NOTE_RANGE; i++) { + if(activeArpNotes[i] != 0) { + // found the next note! + currentArpPosition = i; + break; + } + } + } + + break; + case ARP_DIRECTION_DOWN: + if(activeArpNoteCount == 1) break; + // We just go down and if we reach the first note in the arp, we go forward to the last one + for(int i = currentArpPosition - 1; i >= 0; i--) { + if(activeArpNotes[i] != 0) { + // found the next note! + currentArpPosition = i; + foundNote = true; + break; + } + } + + if(!foundNote) { + // We have to find the last note at the beginning of the arpeggio now... + for(int i = NOTE_RANGE - 1; i >= 0; i--) { + if(activeArpNotes[i] != 0) { + // found the next note! + currentArpPosition = i; + break; + } + } + } + break; + case ARP_DIRECTION_BOTH: + if(activeArpNoteCount == 1) break; + // We just go up and if we reach the last note in the arp, we go back one note + for(int i = currentArpPosition + 1; i < NOTE_RANGE; i++) { + if(activeArpNotes[i] != 0) { + // found the next note! + currentArpPosition = i; + foundNote = true; + break; + } + } + // we are going downwards, so let's search! + if(!foundNote) { + for(int i = currentArpPosition - 1; i >= 0; i--) { + if(activeArpNotes[i] != 0) { + // found the next note! + currentArpPosition = i; + foundNote = true; + break; + } + } + } + + break; + case ARP_DIRECTION_ORDER: + if(activeArpNoteCount == 1) break; + // We find the note that has the least distance to the current notes value. + // If we can't find one, we assign the note with the lowest value + byte minValue = 255; + byte minValueIndex = 0; + for(int i = 0; i < NOTE_RANGE; i++) { + if(i == currentArpPosition || activeArpNotes[i] == 0) continue; + byte distance = abs(activeArpNotes[i] - activeArpNotes[currentArpPosition]); + if(distance < minValue) { + minValue = distance; + minValueIndex = i; + } + } + + if(minValue == 255) { // We did not find a higher note, so let's go back to the first one. + minValue = 0; + for(int i = 0; i < NOTE_RANGE; i++) { + if(i == currentArpPosition || activeArpNotes[i] == 0) continue; + if(activeArpNotes[i] < minValue) { + minValue = activeArpNotes[i]; + minValueIndex = i; + } + } + } + + currentArpPosition = minValueIndex; + break; + case ARP_DIRECTION_RANDOM: + byte newIndex = 0; + + do { + newIndex = random(0, 255); + } while(activeArpNotes[newIndex] == 0 || currentArpPosition == newIndex); + + currentArpPosition = newIndex; + + break; + case ARP_DIRECTION_NONE: + // Noone knows what happens here. + break; + } + + } + gate[0] = HIGH; + + + + + } else { + gate[0] = LOW; + currentArpPosition = 0; + } + + break; + } + + gate[1] = triggerOut ? HIGH : LOW; + gate[2] = midiStartSignal; + gate[3] = midiClockSignal; + + trigger = false; + released = false; + midiStartSignal = LOW; + midiClockSignal = LOW; + + writeDACs(); + writeGates(); +} + +float mapfloat(float x, float in_min, float in_max, float out_min, float out_max) +{ + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +void readSwitches() { + int analogValue = analogRead(PIN_FLIP_SWITCH_0); + if(analogValue < 100) flipSwitch0 = FLIP_SWITCH_UP; + else if(analogValue < 900) flipSwitch0 = FLIP_SWITCH_DOWN; + else flipSwitch0 = FLIP_SWITCH_MIDDLE; + analogValue = analogRead(PIN_FLIP_SWITCH_1); + if(analogValue < 100) flipSwitch1 = FLIP_SWITCH_UP; + else if(analogValue < 900) flipSwitch1 = FLIP_SWITCH_DOWN; + else flipSwitch1 = FLIP_SWITCH_MIDDLE; + + rotarySwitch = (!digitalRead(ROTARY_SWITCH_PIN0) << 2) & (!digitalRead(ROTARY_SWITCH_PIN1) << 1) & !digitalRead(ROTARY_SWITCH_PIN2); +} + +void readSpeed() { + speedValue = analogRead(PIN_SPEED); +} + +void writeDACs() { + dac.SetDAC(cv[0], 1); + dac.SetDAC(cv[1], 2); + dac.SetDAC(cv[2], 3); + dac.SetDAC(cv[3], 4); +} + +void writeGates() { + digitalWrite(PIN_GATE_0, gate[0] == HIGH ? LOW : HIGH); + digitalWrite(PIN_GATE_1, gate[1] == HIGH ? LOW : HIGH); + digitalWrite(PIN_GATE_2, gate[2] == HIGH ? LOW : HIGH); + digitalWrite(PIN_GATE_3, gate[3] == HIGH ? LOW : HIGH); +} diff --git a/README.md b/README.md index 83d3d8e..5a3fdc6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# midi2cv -Eurorack Compatible, Arduino-based midi to cv converter with mono mode, arpeggiator and sequencer - -# Licence - -CC BY 4.0 +# midi2cv +Eurorack Compatible, Arduino-based midi to cv converter with mono mode, arpeggiator and sequencer + +# Licence + +CC BY 4.0 diff --git a/hardware_design/pure_midi.brd b/hardware_design/pure_midi.brd index 7820591..be4abb1 100644 --- a/hardware_design/pure_midi.brd +++ b/hardware_design/pure_midi.brd @@ -6,9 +6,9 @@ - + - + @@ -23,7 +23,7 @@ - + @@ -34,8 +34,8 @@ - - + + @@ -50,13 +50,13 @@ - + - + - - + + @@ -78,84 +78,84 @@ - - - - - - - - - + + + + + + + + + - - - - - + + + + + - - + + - + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + @@ -164,6 +164,8 @@ +Pure MIDI v0.1 +jhbruhn 2018 @@ -3398,8 +3400,10 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf + + - + <b>EAGLE Design Rules</b> <p> Die Standard-Design-Rules sind so gewählt, dass sie für @@ -3417,9 +3421,9 @@ design rules under a new name. - - - + + + @@ -3431,8 +3435,8 @@ design rules under a new name. - - + + @@ -3490,7 +3494,7 @@ design rules under a new name. - + @@ -3663,10 +3667,10 @@ design rules under a new name. - - - - + + + + @@ -3689,10 +3693,10 @@ design rules under a new name. - - - - + + + + @@ -3703,10 +3707,10 @@ design rules under a new name. - - - - + + + + @@ -3717,24 +3721,24 @@ design rules under a new name. - - - - + + + + - - - - + + + + - - - - + + + + @@ -3749,7 +3753,7 @@ design rules under a new name. - + @@ -3765,25 +3769,25 @@ design rules under a new name. - + - + - + - - - + + + - + @@ -3799,11 +3803,11 @@ design rules under a new name. - + - + @@ -3827,7 +3831,7 @@ design rules under a new name. - + @@ -3879,12 +3883,12 @@ design rules under a new name. - + - + @@ -3928,23 +3932,23 @@ design rules under a new name. - - - - - - - + + + + + + + - - - - + + + + - - - - + + + + @@ -3955,32 +3959,32 @@ design rules under a new name. - + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - + @@ -3990,50 +3994,13 @@ design rules under a new name. - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -4087,71 +4054,258 @@ design rules under a new name. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - + + + + + + + + + + + + + + + + + + + + + - + @@ -4163,18 +4317,64 @@ design rules under a new name. - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -4202,361 +4402,1087 @@ design rules under a new name. - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + - + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + - + + + + + + + - + + + + + + + + + + + + + - + + - - + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + - + + - - + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + - + + - - + + + + + - + + + + + + + + + + + + + + + + + - + + + + - - + + + + - + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + - + + + + + + + + + + + + - - + + + + + + - - + + + + - - + + + + + + - + + - - + + + + + + + + + - - + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + - - + + + + + + + + + + + + + + + + + + + + + + + - + + - + + + + + + + + + + - + + + + + - - + + + + - - + + + + - + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + - - + + + + + + + + + - - + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + - - - - + + + + + + + + + - + + + + - + + + + - - + + + + + + + + + + + + + + + + + + + + + + + @@ -4566,67 +5492,280 @@ design rules under a new name. - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + - - + + + + - + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hardware_design/pure_midi.csv b/hardware_design/pure_midi.csv new file mode 100644 index 0000000..0c51b23 --- /dev/null +++ b/hardware_design/pure_midi.csv @@ -0,0 +1,80 @@ +"Part";"Value";"Device";"Package";"Description";"AMBIENT_TEMPERATURE_RANGE_HIGH";"AMBIENT_TEMPERATURE_RANGE_LOW";"CENTROID_NOT_SPECIFIED";"CIIVA_IDS";"CODE__JEDEC";"COMPONENT_LINK_1_DESCRIPTION";"COMPONENT_LINK_1_URL";"COMPONENT_LINK_3_DESCRIPTION";"COMPONENT_LINK_3_URL";"DATASHEET";"DATASHEET_VERSION";"DATA_POLARITY";"DEVICE_CLASS_L1";"DEVICE_CLASS_L2";"DEVICE_CLASS_L3";"DIGIKEY_DESCRIPTION";"DIGIKEY_PART_NUMBER";"FOOTPRINT_PARAMETERS_0";"FOOTPRINT_VARIANT_NAME_0";"FOOTPRINT_VARIANT_NAME_1";"FOOTPRINT_VARIANT_NAME_2";"HEIGHT";"IMPORTED";"IMPORTED_FROM";"IMPORT_TS";"INITIAL_ACCURACY__25DEG_C";"INTERFACE";"IOUT_IZ_MAXM_A";"IPC_LAND_PATTERN_NAME";"LEAD_FREE";"MAX_JUNCTION_TEMP";"MAX_SUPPLY_VOLTAGE";"MF";"MFG_PACKAGE_IDENT";"MFG_PACKAGE_IDENT_DATE";"MFG_PACKAGE_IDENT_REV";"MIN_IZ_FOR_REGULATIONUA";"MIN_SUPPLY_VOLTAGE";"MOUNTING_TECHNOLOGY";"MOUSER_DESCRIPTION";"MOUSER_PART_NUMBER";"MPN";"NUMBER_OF_CHANNELS";"NUMBER_OF_CONVERTERS";"OC_FARNELL";"OC_NEWARK";"PACKAGE";"PACKAGE_DESCRIPTION";"PACKAGE_VERSION";"PIN_0_0_7_INSIDE_EDGE";"PREFIX";"PROD_ID";"RATING";"RELEASE_DATE";"RESOLUTION";"ROHS";"SPICEPREFIX";"STANDOFF_HEIGHT";"SUB_FAMILY";"TEMPERATURE_RANGE_HIGH";"TEMPERATURE_RANGE_LOW";"TEMP_COEFFMAXPPM_DEGREE_C";"TEMP_COEFFTYPPPM_DEGREE_C";"VALUE";"VAULT_GUID";"VAULT_REVISION";"VERIFICATION_VERSION";"VO_V"; +"C1";"22p";"C-EUC0805";"C0805";"CAPACITOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"C";"";"";"";"";"";"";"";"";"";"";""; +"C2";"22p";"C-EUC0805";"C0805";"CAPACITOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"C";"";"";"";"";"";"";"";"";"";"";""; +"C3";"47u";"CAPACITOR_POL-US153CLV-0505";"153CLV-0505";"POLARIZED CAPACITOR, American symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"C4";"47u";"CAPACITOR_POL-US153CLV-0505";"153CLV-0505";"POLARIZED CAPACITOR, American symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"C5";"47u";"CAPACITOR_POL-US153CLV-0505";"153CLV-0505";"POLARIZED CAPACITOR, American symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"C6";"47u";"CAPACITOR_POL-US153CLV-0505";"153CLV-0505";"POLARIZED CAPACITOR, American symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"C7";"22p";"C-EUC0805";"C0805";"CAPACITOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"C";"";"";"";"";"";"";"";"";"";"";""; +"C8";"22p";"C-EUC0805";"C0805";"CAPACITOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"C";"";"";"";"";"";"";"";"";"";"";""; +"C9";"100n";"C-EUC0805";"C0805";"CAPACITOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"C";"";"";"";"";"";"";"";"";"";"";""; +"C10";"100n";"C-EUC0805";"C0805";"CAPACITOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"C";"";"";"";"";"";"";"";"";"";"";""; +"C11";"100n";"C-EUC0805";"C0805";"CAPACITOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"C";"";"";"";"";"";"";"";"";"";"";""; +"C12";"100n";"C-EUC0805";"C0805";"CAPACITOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"C";"";"";"";"";"";"";"";"";"";"";""; +"C13";"100n";"C-EUC0805";"C0805";"CAPACITOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"C";"";"";"";"";"";"";"";"";"";"";""; +"C14";"100n";"C-EUC0805";"C0805";"CAPACITOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"C";"";"";"";"";"";"";"";"";"";"";""; +"C15";"100n";"C-EUC0805";"C0805";"CAPACITOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"C";"";"";"";"";"";"";"";"";"";"";""; +"C16";"100n";"C-EUC0805";"C0805";"CAPACITOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"C";"";"";"";"";"";"";"";"";"";"";""; +"D1";"1N4148";"DIODESOD-323F";"SOD-323F";"Diode";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"D2";"1N4001";"DIODESMA";"SMADIODE";"Diode";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"D3";"1N4001";"DIODESMA";"SMADIODE";"Diode";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"IC1";"74HCT125D";"74HCT125D";"SO14";"Quad bus BUFFER, 3-state";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"IC1_33";"VOLTAGE_REG_POSDT";"VOLTAGE_REG_POSDT";"TO252";"Positive VOLTAGE REGULATOR";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"IC2";"VOLTAGE_REG_POS05DT";"VOLTAGE_REG_POS05DT";"TO252";"Positive VOLTAGE REGULATOR";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"IC3";"74HC148D";"74HC148D";"SO16";"10-line to 4-line and 8-line to 3-line PRIORITY ENCODER";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"IC4";"74HCT125D";"74HCT125D";"SO14";"Quad bus BUFFER, 3-state";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"ISP1";"AVRISP-6";"AVRISP-6";"AVRISP";"AVR ISP HEADER";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"JP1";"";"JP1E";"JP1";"JUMPER";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"OK1";"6N138";"6N138";"DIL08";"MOTOROLA OPTO COUPLER";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"VISHAY/TELEFUNKEN";"";"";"";"";"";"";"";"";"6N138";"";"";"9860150";"35K5294";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"PWR1";"HEADER2X5SHD";"HEADER2X5SHD";"2X5-SHROUDED";"Header 5x2";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"Q1";"20MHz";"CRYSTALHC49UP";"HC49UP";"CRYSTAL";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"unknown";"unknown";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"Q2";"12MHz";"CRYSTALHC49UP";"HC49UP";"CRYSTAL";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"unknown";"unknown";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"R1";"2k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R2";"4k7";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R3";"1k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R4";"1k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R5";"1k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R6";"1k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R7";"1k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R8";"1k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R9";"1k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R10";"1k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R11";"220R";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"R12";"470R";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"R13";"10k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"R14";"10k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"R15";"10k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"R16";"10k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"R17";"1k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"R18";"10k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R19";"10k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R20";"10k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R21";"10k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R22";"10k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R23";"10k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R24";"10k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R25";"10k";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R26";"33R";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"R27";"33R";"R-EU_R0805";"R0805";"RESISTOR, European symbol";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"R";"";"";"";"";"";"";"";"";"";"";""; +"T1";"MMBT3904";"-NPN-SOT23-EBC";"SOT23-EBC";"NPN Transistror";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"T2";"MMBT3904";"-NPN-SOT23-EBC";"SOT23-EBC";"NPN Transistror";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"T3";"MMBT3904";"-NPN-SOT23-EBC";"SOT23-EBC";"NPN Transistror";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"T4";"MMBT3904";"-NPN-SOT23-EBC";"SOT23-EBC";"NPN Transistror";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"U$1";"WQP-PJ301M-12_JACK";"WQP-PJ301M-12_JACK";"WQP-PJ301M-12_JACK";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"U$2";"WQP-PJ301M-12_JACK";"WQP-PJ301M-12_JACK";"WQP-PJ301M-12_JACK";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"U$3";"WQP-PJ301M-12_JACK";"WQP-PJ301M-12_JACK";"WQP-PJ301M-12_JACK";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"U$4";"WQP-PJ301M-12_JACK";"WQP-PJ301M-12_JACK";"WQP-PJ301M-12_JACK";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"U$5";"WQP-PJ301M-12_JACK";"WQP-PJ301M-12_JACK";"WQP-PJ301M-12_JACK";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"U$6";"WQP-PJ301M-12_JACK";"WQP-PJ301M-12_JACK";"WQP-PJ301M-12_JACK";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"U$7";"WQP-PJ301M-12_JACK";"WQP-PJ301M-12_JACK";"WQP-PJ301M-12_JACK";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"U$8";"WQP-PJ301M-12_JACK";"WQP-PJ301M-12_JACK";"WQP-PJ301M-12_JACK";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"U$9";"TOGGLE_ON_OFF_ON";"TOGGLE_ON_OFF_ON";"TOGGLE_ON_OFF_ON";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"U$10";"TOGGLE_ON_OFF_ON";"TOGGLE_ON_OFF_ON";"TOGGLE_ON_OFF_ON";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"U$11";"Q-POT";"Q-POT";"Q-POT";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"U$12";"ALPS-SRBV";"ALPS-SRBV";"ALPS-SRBV";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"U1";"ANALOG_DEVICES_INC_AD5754AREZANALOG_DEVICES_INC_AD5754AREZ_0_0";"ANALOG_DEVICES_INC_AD5754AREZANALOG_DEVICES_INC_AD5754AREZ_0_0";"ANALOG_DEVICES_INC_AD5754AREZ_0";"DAC 4-CH Resistor-String 16-bit 24-Pin TSSOP EP";"+85°C";"-40°C";"No";"";"";"";"";"";"";"http://www.analog.com/media/en/technical-documentation/data-sheets/AD5724_5734_5754.pdf";"";"Unipolar/Bipolar";"Integrated Circuits (ICs)";"Data Converter ICs";"Digital to Analog Converters (DACs)";"IC DAC 16BIT DSP/SRL 24TSSOP";"AD5754AREZ-ND";"{"fp_type":"TSSOP2","params":{"N":{"nom":24,"long name":"Number of leads","min":null,"max":null,"short name":"N","type":"count"},"A":{"nom":false,"long name":"Height","min":false,"max":1200000,"short name":"A","type":"measurement"},"A1":{"nom":false,"long name":"Package clearance","min":50000,"max":150000,"short name":"A1","type":"measurement"},"A2":{"nom":1000000,"long name":"Package height","min":800000,"max":1050000,"short name":"A2","type":"measurement"},"D":{"nom":7800000,"long name":"Package length","min":7700000,"max":7900000,"short name":"D","type":"measurement"},"E":{"nom":6400000,"long name":"Width /w leads","min":false,"max":false,"short name":"E","type":"measurement"},"E1":{"nom":4400000,"long name":"Package width","min":4300000,"max":4500000,"short name":"E1","type":"measurement"},"B":{"nom":false,"long name":"Lead width","min":190000,"max":300000,"short name":"B","type":"measurement"},"C":{"nom":false,"long name":"Lead thickness","min":90000,"max":200000,"short name":"C","type":"measurement"},"L":{"nom":600000,"long name":"Lead foot length","min":450000,"max":750000,"short name":"L","type":"measurement"},"e":{"nom":650000,"long name":"Lead pitch","min":null,"max":null,"short name":"e","type":"measurement"},"PHI":{"nom":false,"long name":"Lead angle","min":0,"max":8,"short name":"PHI","type":"measurement"},"D2":{"nom":5000000,"long name":"Thermal pad length","min":4950000,"max":5020000,"short name":"D2","type":"measurement"},"E2":{"nom":3200000,"long name":"Thermal pad width","min":3150000,"max":3250000,"short name":"E2","type":"measurement"},"PC":{"long name":"Paste coverage (%)","type":"percentage","short name":"PC","value":40},"HT":{"default":"Yes","long name":"Thermal pad","type":"multichoiceparent","short name":"HT","children":["D2","E2","PC"]},"offset x":{"nom":0,"long name":"X Center offset","min":null,"max":null,"short name":"offset x","type":"measurement"},"offset y":{"nom":0,"long name":"Y Center offset","min":null,"max":null,"short name":"offset y","type":"measurement"},"LS":{"default":"Rounded rectangle","long name":"Land shape","type":"multichoice","short name":"LS"},"LS1":{"default":"Rectangle","long name":"Land shape (Pin 1)","type":"multichoice","short name":"LS1"},"solder toe":{"nom":150000,"long name":"Solder fillet (toe)","min":null,"max":null,"short name":"solder toe","type":"fixedmeasurement"},"solder heel":{"nom":250000,"long name":"Solder fillet (heel)","min":null,"max":null,"short name":"solder heel","type":"fixedmeasurement"},"solder side":{"nom":10000,"long name":"Solder fillet (side)","min":null,"max":null,"short name":"solder side","type":"fixedmeasurement"},"courtyard":{"nom":100000,"long name":"Courtyard","min":null,"max":null,"short name":"courtyard","type":"fixedmeasurement"},"SF":{"default":"C","long name":"Packing level","type":"multichoiceparent","short name":"SF","help":"http://support.upverter.com/customer/portal/articles/978783-what-is-a-footprint-packing-level","children":["solder toe","solder heel","solder side","courtyard"]}}}";"";"";"";"1.2mm";"";"";"";"";"SPI,Other";"";"SOP65P640X120-24";"yes";"+150°C";"16.5V";"Analog Devices Inc";"RE-24";"0";"A";"";"2.7V";"";"Digital to Analog Converters - DAC IC Dual 16-Bit VOut";"584-AD5754AREZ";"AD5754AREZ";"4";"4";"";"";"TSSOP24";"";"";"clock";"U";"";"";"";"16b";"yes";"";"0.05mm";"";"+85°C";"-40°C";"";"";"";"";"";"0.0.0.1";""; +"U2";"TEXAS_INSTRUMENTS_LM4040C25IDBZRTEXAS_INSTRUMENTS_LM4040C25IDBZR_0_1";"TEXAS_INSTRUMENTS_LM4040C25IDBZRTEXAS_INSTRUMENTS_LM4040C25IDBZR_0_1";"TEXAS_INSTRUMENTS_LM4040C25IDBZR_1";"TI-LM4040C25DBZ3";"";"";"";"1469524";"TO-236";"Manufacturer URL";"http://www.ti.com/";"Package Specification";"http://www.ti.com/litv/pdf/mpds108a";"http://www.ti.com/general/docs/lit/getliterature.tsp?genericPartNumber=LM4040C25&fileType=pdf";"SLOS456K";"";"";"";"";"";"";"";"Level C";"Level B";"Level A";"";"yes";"vault";"1521848919";"0.5";"";"15";"";"";"";"";"Texas Instruments";"";"";"";"75";"";"Surface Mount";"";"";"LM4040C25IDBZR";"";"";"";"";"DBZ0003A";"3-Pin Plastic Small Outline, Body 2.92 x 1.3 mm, Pitch 0.95 mm";"4203227/B";"";"U";"";"Catalog";"1464596443";"";"Yes";"";"";"Shunt Voltage Reference";"";"";"100";"15";"";"5413DB6E-9D10-4027-A969-08E6820F4111";"C65482E3-4B49-4B9C-954A-31B6BAF04754";"";"2.5"; +"U3";"ATMEGA328P_TQFP";"ATMEGA328P_TQFP";"TQFP32-08";"Popular 328P in QFP";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"IC-09069";"";"";"";"";"";"";"";"";"";"";"";"ATMEGA328P_TQFP";"";"";"";""; +"U4";"MAX3421";"MAX3421ESMD";"TQFP32-5MM";"MAX3421EEHJ";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"IC-09517";"";"";"";"";"";"";"";"";"";"";"";"MAX3421";"";"";"";""; +"X1";"OG-MIDI_MAB5SHCUI-SD-50BV";"OG-MIDI_MAB5SHCUI-SD-50BV";"OG-MIDI_SD-50BV";"Female CONNECTOR";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; +"X2";"KUSBVX";"KUSBVX";"KUSBVX";"Vertical,Top Entry Universal Serial Bus Connector KUSBVX Series";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";"";""; diff --git a/hardware_design/pure_midi.sch b/hardware_design/pure_midi.sch index 8311ba3..e4a2139 100644 --- a/hardware_design/pure_midi.sch +++ b/hardware_design/pure_midi.sch @@ -25775,6 +25775,8 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf + + @@ -25932,6 +25934,7 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf + @@ -26110,7 +26113,7 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf - + @@ -26165,8 +26168,13 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf + + + + + - + @@ -26222,13 +26230,6 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf - - - - - - - @@ -26585,7 +26586,36 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -26670,38 +26700,7 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -26719,7 +26718,7 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf - + @@ -26756,7 +26755,7 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf - + @@ -27077,7 +27076,7 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf - + @@ -27089,7 +27088,7 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf - + @@ -27182,7 +27181,7 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf - + @@ -27291,7 +27290,7 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf - + @@ -27472,11 +27471,14 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf + + + - + @@ -27585,13 +27587,6 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf - - - - - - @@ -27729,6 +27724,7 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf + @@ -27752,6 +27748,11 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf + + + + @@ -27773,14 +27774,7 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf - - - - - - - + @@ -27790,6 +27784,13 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf + + + + @@ -27884,7 +27885,7 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf - + @@ -27896,7 +27897,7 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf - + @@ -27909,7 +27910,7 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf - + @@ -27930,7 +27931,7 @@ Source: KYCON Sibalco USB vertical socket KUSBV.pdf - + diff --git a/hardware_design/pure_midi_2018-11-19.zip b/hardware_design/pure_midi_2018-11-19.zip new file mode 100644 index 0000000..1d7e4cb Binary files /dev/null and b/hardware_design/pure_midi_2018-11-19.zip differ