The BIG Arduino MIDI controller thread - Page 3
Page 3 of 16 FirstFirst 123456713 ... LastLast
Results 21 to 30 of 155
  1. #21
    Tech Mentor
    Join Date
    Feb 2011
    Location
    Southern Ontario, Canada
    Posts
    244

    Default

    I won't hijack this thread, but I just wanted to say that I am in the process of designing my final prototype controller (having already built and tested 3 different versions of it -- pic below). I have found it to be a very very fun and educational project. I'll likely end up posting my own build log since mine is substantially larger (full 4 channel, i'm only done the basics and i'm up to 64 buttons, 16 pots and 5 faders [4x60mm, 1x100mm]), and I hate hijacking threads, nice job on yours so far though, if you need any assistance let me know

    L-R: Behringer DX-500-M (-M for midi ), quick transport test controller i whipped up last night, code and electronic prototype (used to test code/schematics, and has obviously gone through changes).

    Here is the current state of my final prototype.. lots of room for transport/fx/global controls

  2. #22
    Tech Guru MiL0's Avatar
    Join Date
    May 2009
    Location
    Brighton / Bangkok
    Posts
    1,386

    Default

    that's not hijacking - that's exactly the kind of project that should be posted in this thread!!

    would you be willing to share the code you used? can you give any more details about how its all wired up? looks like you've wired up some midi ports? did you create your own mux shield to get more inputs out of the arduino? how about some close up shots of the wiring?

    welcome to the forum btw - great first post

  3. #23
    Tech Mentor
    Join Date
    Feb 2011
    Location
    Southern Ontario, Canada
    Posts
    244

    Default

    Quote Originally Posted by MiL0 View Post
    that's not hijacking - that's exactly the kind of project that should be posted in this thread!!
    Well okay then!

    Quote Originally Posted by MiL0 View Post
    would you be willing to share the code you used
    Open Source for the win my friend... the (current) code is in my next post (for the breadboard prototype, the other controllers use code that is pretty much identical). Be aware that while it is working and fairly fast (it checks all inputs and sends midi out in an average of 1.2 milliseconds, or about 50,000 times per second), it is not what I consider good looking code, and will be re-factored and cleaned up quite a bit...

    Quote Originally Posted by MiL0 View Post
    can you give any more details about how its all wired up?
    I'll do ya one better, below is an old (but it should work) schematic for a bunch of pots and buttons, it doesnt include the midi-in circuit or the rotary encoder circuit (the touch pad gets wired to +5v, GND and two digital pins).

    It's not what is on the breadboard right now, but it is similar.

    Quote Originally Posted by MiL0 View Post
    looks like you've wired up some midi ports?
    Yeppers! Midi out is dead simple (once you've figured out that most schematics for midi out shows the connector FROM THE BACK, not the front as most assume).

    Midi-In was another matter... there are a number of bad schematics out there, I ended up using a 4N35 optoisolator, with a 270r input resistor (for the input led) and a 1k pull-up for the transistor side. It works great... chained two three controllers together and there was ZERO latency... I'll put up a schematic for it later today.

    Quote Originally Posted by MiL0 View Post
    did you create your own mux shield to get more inputs out of the arduino?
    Not really, but I suppose the idea is the same... I am (currently) using 4 IC's to handle the buttons, pots and faders, 2x CD4021 allow 8 DIGITAL inputs each (daisy chain-able, so two gives me 16 inputs using 3 digital pins on the atmega), 2x CD4051 give me 8 ANALOG inputs each to handle the pots and faders... so that's a total of 32 inputs using a total of 8 pins (3 for the 4021's, 3 for both 4051's and 1 analog input for each 4051). I can easily extend that to many many more (adding two more of each would give me 32 buttons and 32 pots/faders), with the only limit being how fast you can deal with the many inputs...


    Quote Originally Posted by MiL0 View Post
    how about some close up shots of the wiring?
    Ask and yee shall receive! (see bottom of post)

    Quote Originally Posted by MiL0 View Post
    welcome to the forum btw - great first post
    Thanks, glad to be here!

    If you have any other questions, please just ask away!

    Schematic:


    Better pic of the prototype:


    Wiring:




    Midi Out:


    Midi In:


    Guts of the prototype:


    Stock on the front:


    Almost stock on the back:


    Not so stock on the inside:


    Behringer would never do this:


    Closeup of DX-500-M guts:


    One more closeup:


    My custom breadboard arduino:

  4. #24
    Tech Mentor
    Join Date
    Feb 2011
    Location
    Southern Ontario, Canada
    Posts
    244

    Default

    Here's the code:

    Code:
    /*
    TODO
    Refactor input code turn everthing into functions for easier maintanance and fewer global variables
    Add an initial calibration routine to prevent initial flood of midi data on startup
    Rethink encoder code, it seems to be a little slow
    Possible issue with encoder buttons
    Implement messages queue'ing system to buffer messages before sending (possible resolution to encoder issue)
    */
    
    //#include <ps2.h>
    //#include <Trackpad.h>
    #include <WProgram.h>
    #include <Midi.h>
    
    #define NUM_POTS 13  
    #define NUM_BUTTONS 16
    #define BTN_DEBOUNCE 75
    #define NUM_ENCODERS 2
    #define SMOOTHING 3
    #define POT_SELECT_PINS {2,3,4}; //A, B, C on 4051
    #define POT_READ_PINS {0,1}
    #define MIDI_CHANNEL 1
    #define XY_SENSITIVITY 25
    #define XY_CC_X 71 // xy pad X CC#
    #define XY_CC_Y 70 // xy pad Y CC#
    #define XY_NOTE 69 // A-4
    #define XY_MIN_X 1320
    #define XY_MAX_X 5480
    #define XY_MIN_Y 1245
    #define XY_MAX_Y 4490
    #define XY_CLOCK 18 // Orange Wire
    #define XY_LATCH 19 // Blue Wire
    #define ENC1_A 8
    #define ENC1_B 9
    #define ENC2_A 8
    #define ENC2_B 9
    #define ENC_PORT PINB
    #define ENC_MODE_REL 1
    #define ENC_MODE_ABS 2
    #define ENC_MODE ENC_MODE_REL
    #define CW 0b01
    #define CCW 0b11
    #define CLOCK_4021 7
    #define LATCH_4021 6 
    #define DATA_4021 5
    #define ON 0
    #define OFF 1
    
    /* Debug Defines */
    #define DEBUG_POT 1
    #define DEBUG_BTN 2
    #define DEBUG_PAD 4
    #define DEBUG_ENC 8
    #define DEBUG_ALL 15
    #define DEBUG false
    #define BENCH false
    #define DEBUG_SEL DEBUG_POT
    /* Debug Defines */
    
    class MyMidi : public Midi {
      public:
      MyMidi(HardwareSerial &s) : Midi(s) {}
      void handleNoteOn(unsigned int channel, unsigned int note, unsigned int velocity) {
        sendNoteOn(channel, note, velocity);
      }
      void handleNoteOff(unsigned int channel, unsigned int note, unsigned int velocity) {
        sendNoteOff(channel, note, velocity);
      }
      void handleControlChange(unsigned int channel, unsigned int controller, unsigned int value) {
        sendControlChange(channel, controller, value);
      }
    };
    
    /* returns byte: bits 1,2 are encoder 1... bits 2,3 are encoder 2... 0b11 is CCW 0b01 is CW */
    byte read_two_encoders() {
      int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
      static uint8_t old_AB1, old_AB2 = 0;
      byte rtn = 0;
    
      old_AB1 <<= 2; //remember previous state
      old_AB1 |= (ENC_PORT & 0b11); //add current state
      old_AB2 <<= 2; //remember previous state
      old_AB2 |= (ENC_PORT & 0b1100) >> 2; //add current state
      rtn |= (enc_states[(old_AB1 & 0b1111)]) & 0b11;
      return rtn | ((enc_states[(old_AB2 & 0b1111)]) & 0b11) << 2;
    }
    
    //Trackpad xyPad(XY_CLOCK, XY_LATCH);
    MyMidi midi(Serial);
    byte potReadPins[] = POT_READ_PINS;
    byte potSelectPins[] = POT_SELECT_PINS;
    byte buttons1, lastButtons = B11111111; // Default state of buttons
    byte buttons2 = B11111111; // Default state of buttons
    byte encValues[NUM_ENCODERS] = {1,1}; 
    byte prevEncValues[NUM_ENCODERS] = {1,1}; 
    byte counter = 0; // for benchmarking
    boolean buttonState[NUM_BUTTONS] = {};
    boolean lastButtonState[NUM_BUTTONS] = {};
    int potValues[NUM_POTS] = {};
    int prevPotValues[NUM_POTS] = {};
    unsigned int allButtons = 0;
    unsigned long lastBtn = 0; // for debouncing buttons
    unsigned long current = 0; // for benchmarking
    unsigned long running = 0; // for benchmarking
    unsigned long benchmarks[4] = {0,0,0,0};
    
    
    void setup() {
      if (DEBUG||BENCH) Serial.begin(38400);
      else midi.begin(0);
      pinMode(LATCH_4021, OUTPUT);
      pinMode(CLOCK_4021, OUTPUT);
      pinMode(DATA_4021, INPUT);
      pinMode(ENC1_A, INPUT);
      pinMode(ENC1_B, INPUT);
      pinMode(ENC2_A,INPUT);
      pinMode(ENC2_B,INPUT);
      for (byte i=0;i < 3;i++) pinMode(potSelectPins[i], OUTPUT);
      for (byte i=0;i < NUM_POTS;i++) potValues[i] = prevPotValues[i] = 0;
      for (byte i=0;i < NUM_BUTTONS;i++) buttonState[i] = lastButtonState[i] = 1;
      if (DEBUG||BENCH) Serial.println("Begin");
    }
    
    void loop() {
      if (BENCH) current = micros();
      midi.poll();
    /*--------------|  BUTTONS  |--------------*/
      digitalWrite(LATCH_4021,1);delayMicroseconds(20);digitalWrite(LATCH_4021,0);
      buttons1 = shiftIn(DATA_4021, CLOCK_4021, LSBFIRST);
      buttons2 = shiftIn(DATA_4021, CLOCK_4021, LSBFIRST);
      allButtons = word(buttons1, buttons2);
      if ((allButtons != lastButtons) && (micros() - lastBtn > BTN_DEBOUNCE)) {
        lastBtn = micros();lastButtons = allButtons;
        for (byte i=0;i<NUM_BUTTONS;i++){
          if (!bitRead(allButtons, i)) buttonState[i] = ON;
          else buttonState[i] = OFF;
          if (buttonState[i] != lastButtonState[i]) {
            lastButtonState[i] = buttonState[i];
            if (buttonState[i] == OFF) {
              if (DEBUG && (DEBUG_SEL & DEBUG_BTN)) {Serial.print("Button ");Serial.print(i+1,DEC);Serial.println(": OFF");}
              else midi.sendNoteOff(MIDI_CHANNEL, i, 0); // Stop the note
            } else {
              if (DEBUG && (DEBUG_SEL & DEBUG_BTN)) {Serial.print("Button ");Serial.print(i+1,DEC);Serial.println(": ON");}
              else midi.sendNoteOn(MIDI_CHANNEL, i, 127); // Send the note
            }
          }
        }
      }
      if (BENCH) {
        benchmarks[0] += micros()-current;
        current = micros();
      }
    /*--------------|  BUTTONS  |--------------*/
    /*--------------|  POTS  |--------------*/
      byte chipSelect = 0;
      for(int i = 0; i < NUM_POTS; i++) {
        PORTD = (NUM_POTS > 8 && i >= 8) ? (i % 8) << 2 : i << 2; // set pins 2, 3 and 4 to value between 0 (00000) and 7 (11100) to select the pot
        if (i > 0 && (i % 8 == 0)) chipSelect++; // increase chip select index every 8 pots
        potValues[i] = analogRead(potReadPins[chipSelect]);
        if (abs(potValues[i] - prevPotValues[i]) > SMOOTHING) {
          prevPotValues[i] = potValues[i];
          if (!DEBUG) midi.sendControlChange(MIDI_CHANNEL, i, map(potValues[i],5,1020,0,127));
        }
        if (DEBUG && (DEBUG_SEL & DEBUG_POT)) {Serial.print(" P");Serial.print(i+1,DEC);Serial.print(":");Serial.print(potValues[i],DEC);}
      }
      if (DEBUG && (DEBUG_SEL & DEBUG_POT)) Serial.println();  
      if (BENCH) {
        benchmarks[1] += micros()-current;
        current = micros();
      }
    /*--------------|  POTS  |--------------*/
    /*--------------|  Encoders  |--------------*/
      static byte encoderCnt = 0;
      byte enc1,enc2,encValue = 0;
      encValue = read_two_encoders();
      if(encValue && (++encoderCnt % 4) == 0) {
        enc1 |= encValue & 0b11;
        if (enc1 == CW) {
          if (ENC_MODE & ENC_MODE_REL) {
            if (DEBUG && (DEBUG_SEL & DEBUG_ENC)) Serial.println("ENC1: ->");
            else midi.sendControlChange(MIDI_CHANNEL,30,1);
          }
          if (ENC_MODE & ENC_MODE_ABS) {
            encValues[0]++;
            if(encValues[0] >= 127) encValues[0] -= 127;
            midi.sendControlChange(MIDI_CHANNEL,40,encValues[0]);
          }
        } else if (enc1 == CCW) {
          if (ENC_MODE & ENC_MODE_REL) {
            if (DEBUG && (DEBUG_SEL & DEBUG_ENC)) Serial.println("ENC1: <-");
            else midi.sendControlChange(MIDI_CHANNEL,30,127);
          }
          if (ENC_MODE & ENC_MODE_ABS) {
            encValues[0]--;
            if(encValues[0] <= 0) encValues[0] += 127;    
            midi.sendControlChange(MIDI_CHANNEL,40,encValues[0]);
          }
        }
    
        enc2 |= (encValue >> 2) & 0b11;  
        if (enc2 == CW) {
          if (ENC_MODE & ENC_MODE_REL) {
            if (DEBUG && (DEBUG_SEL & DEBUG_ENC)) Serial.println("ENC2: ->");
            else midi.sendControlChange(MIDI_CHANNEL,31,1);
          }
          if (ENC_MODE & ENC_MODE_ABS) {
            encValues[1]++;
            if(encValues[1] >= 127) encValues[1] -= 127;
            midi.sendControlChange(MIDI_CHANNEL,41,encValues[1]);
          }
        } else if (enc2 == CCW) {
          if (ENC_MODE & ENC_MODE_REL) {
            if (DEBUG && (DEBUG_SEL & DEBUG_ENC)) Serial.println("ENC2: <-");
            else midi.sendControlChange(MIDI_CHANNEL,31,127);
          }
          if (ENC_MODE & ENC_MODE_ABS) {
            encValues[1]--;
            if(encValues[1] <= 0) encValues[1] += 127;    
            midi.sendControlChange(MIDI_CHANNEL,41,encValues[1]);
          }
        }
      }
      if (BENCH) {
        benchmarks[3] += micros()-current;
        current = micros();
      }
    /*--------------|  Encoders  |--------------*/
    ///*--------------|  XY Pad  |--------------*/
    //  packet_t * packet;
    //  packet = xyPad.getNewPacket();
    //  static boolean xyOn = false;
    //  if (packet->z > XY_SENSITIVITY) {
    //    if (!xyOn) {
    //      xyOn = true;
    //      if (DEBUG && (DEBUG_SEL & DEBUG_PAD)) Serial.println("XY Pad ON");
    //      else midi.sendNoteOn(MIDI_CHANNEL, XY_NOTE, 127);
    //    }
    //    if (DEBUG && (DEBUG_SEL & DEBUG_PAD)) {
    //      Serial.print("X: ");Serial.print(packet->x,DEC);Serial.print(" Y: ");Serial.println(packet->y,DEC);
    //    } else {
    //      midi.sendControlChange(MIDI_CHANNEL, XY_CC_X, constrain(map(packet->x, XY_MIN_X, XY_MAX_X, 0, 127), 0, 127));
    //      midi.sendControlChange(MIDI_CHANNEL, XY_CC_Y, constrain(map(packet->y, XY_MIN_Y, XY_MAX_Y, 0, 127), 0, 127));
    //    }
    //  } else {
    //    if (xyOn) {
    //      xyOn = false;
    //      if (DEBUG && (DEBUG_SEL & DEBUG_PAD)) Serial.println("XY Pad OFF");
    //      else midi.sendNoteOff(MIDI_CHANNEL, XY_NOTE, 0);
    //    }
    //  }
    //  if (BENCH) {
    //    benchmarks[2] += micros()-current;
    //    current = micros();
    //  }
    ///*--------------|  X/Y Pad  |--------------*/
      if (BENCH) {
        counter++;
        if (counter >= 10) {
          Serial.print("(ms) Btn: ");Serial.print(benchmarks[0]/counter,DEC);
          Serial.print(" Pot: ");Serial.print(benchmarks[1]/counter,DEC);
    //      Serial.print(" Pad: ");Serial.print(benchmarks[2]/counter,DEC);
          Serial.print(" Enc: ");Serial.println(benchmarks[3]/counter,DEC);
          counter = benchmarks[0] = benchmarks[1] = benchmarks[2] = benchmarks[3] = 0;
        }
      }
    }

  5. #25
    Tech Guru Archies'bald's Avatar
    Join Date
    May 2009
    Location
    Scotland
    Posts
    686

    Default

    Erm.... could someone pick my jaw up from the floor please? Lovely work.

    How long has it taken you to this point DJNecro?

  6. #26
    Tech Mentor safefire's Avatar
    Join Date
    Aug 2010
    Posts
    259

    Default

    Yay, Eagle

    Looks like you're making good progress mate. Nice to see someone take some stuff out of their head and down on paper.

    I'm about hit the hay, so I'll leave the majority of my questions till the morning.

    One thing I'd like to know though is, which pots and faders are you using?
    I've been shopping around for good quality analog inputs. The only models I can find which looks relatively well made are Bourns, and those I can't buy in quantities under 120+.

    I'm very excited about your project. I'll have nothing short of a thousand questions ready for you tomorrow, regarding 40XXN chips, boards and that touch screen.

    Keep up the good work
    Fixing stuff that isn't broken.

  7. #27
    Tech Mentor
    Join Date
    Feb 2011
    Location
    Southern Ontario, Canada
    Posts
    244

    Default

    Quote Originally Posted by Archies'bald View Post
    Erm.... could someone pick my jaw up from the floor please? Lovely work.

    How long has it taken you to this point DJNecro?
    The midi stuff is about 8-12 weeks of time so far (sporadic since it's currently a hobby), overall electronics/arduino stuff? just over a year... all self taught.


    Quote Originally Posted by safefire View Post
    Yay, Eagle

    Looks like you're making good progress mate. Nice to see someone take some stuff out of their head and down on paper.

    I'm about hit the hay, so I'll leave the majority of my questions till the morning.

    One thing I'd like to know though is, which pots and faders are you using?
    I've been shopping around for good quality analog inputs. The only models I can find which looks relatively well made are Bourns, and those I can't buy in quantities under 120+.

    I'm very excited about your project. I'll have nothing short of a thousand questions ready for you tomorrow, regarding 40XXN chips, boards and that touch screen.

    Keep up the good work
    Nothing special for the prototype, that is a question I have myself... I only know that I'll be using ALPS pots/faders/encoders, and likely buttons too, but I find it harder to buy buttons online, as its not as much the look but the feel of the button that is most important... it's tough to push a button over the intertubes these days... I'd love to use arcade buttons, but they are way too pricey in the qty i'd be buying, and their size!!! oh so big... lol

    I am not too sure how much 'quality' is required when we're dealing with digital electronics... as long as it has a smooth taper, the rest is up to the software... that being said, physical construction (metal, not plastic crappyness) is always important. If you wanted to use the pots to build a true analog mixer, then yeah... quality all the way since sound is going through them... for us, we're sending 1's and 0's, the arduino reads a pot and gives back a value from 0-1023, nothing more, nothing less... if anything I would say the adc (analog-digital converter) of the atmega chip (or whatever processor is being used) is more important, the higher precision, the better (atmega's use 10bit, others use 12bit or more)..

    Gotta.... Stop.... Rambling...

    Oh, and it's a touchpad (ripped out of a notebook), NOT a touch screen... though that would be sick
    Last edited by DjNecro; 02-08-2011 at 05:30 PM.

  8. #28
    Tech Mentor safefire's Avatar
    Join Date
    Aug 2010
    Posts
    259

    Default

    I know what you mean about the quality of the analog parts.
    What I meant was more that, with manufacturers like ALPS, most of their datasheets are so groggy and incomplete that I have a hard time believing the quality of their mechanical parts.

    RS-Components sell ALPS parts and a few Bourns as well. They sell in mostly reasonable quantities (1-10+), and ship at reasonable rates. Oh well.

    your 40XXN chips, are those just generic ADCs or? What are your experiences with these?

    As well, since you're drawing up things in eagle, I assume you've put some work into designing the PCBs as well?

    Your workflow looks very similar to mine, too. I'm quite well versed in drawing up schematics and plans for controllers, cases and parts, if you'd like some help getting things laid out nice and tidy, give me a shout

    Keep up the good work
    Fixing stuff that isn't broken.

  9. #29
    Tech Mentor
    Join Date
    Feb 2011
    Location
    Southern Ontario, Canada
    Posts
    244

    Default

    Quote Originally Posted by safefire View Post
    I know what you mean about the quality of the analog parts.
    What I meant was more that, with manufacturers like ALPS, most of their datasheets are so groggy and incomplete that I have a hard time believing the quality of their mechanical parts.
    I havent found the datasheets lacking (at least for their buttons and pots), the mechanical drawings are very precise and complete, and as for electrically... ground, power, signal... 99% of pots are wired the same, outside contacts are for ground/power and the centre is signal...

    Unless you are referring to more detailed information such as force required to push/turn, etc...

    Quote Originally Posted by safefire View Post
    RS-Components sell ALPS parts and a few Bourns as well. They sell in mostly reasonable quantities (1-10+), and ship at reasonable rates. Oh well.
    If I can find buttons and pots for just under a dollar a piece in quantity (for my final prototype I am expecting 70+ pots and nearly 200 buttons), that would be ideal... I always wondered how companies justify $500+ for a 'simple' controller... Then I researched the component prices, and unless I am building thousands of controllers (10's of thousands of buttons), I doubt I could be competitive...

    Quote Originally Posted by safefire View Post
    your 40XXN chips, are those just generic ADCs or? What are your experiences with these?
    The 4021's are digital (de)multiplexers, think of them like a network switch. you connect 8 (or more) buttons to the inputs of the 4021, and then ask it for the current state. It reads all the inputs in parallel (all 8 at once), then spits it back out serially (one at a time).

    The 4051's are their analog counterparts. Hook 8 (or more) analog sources to the inputs, and then one by one you go through the inputs and read them. Internally, the chip will switch each input to a common output (which is connected to an analog input on the arduino). Then its just a simple analogRead() to grab the value.

    It sounds a little complicated, but once you've played with them (they are cheaper than dirt, pick some up!) and seen how the code works it becomes second nature...

    The fun part comes when you daisy chain them together My final controller will likely use an even bigger IC that has 32 inputs, so 4 for pots and faders, 6-8 for buttons and i'll be set let's just say that using 10 (5 each) of the larger ic's you could have 160 buttons and 160 pots/faders using only 9 digital inputs and 5 analog inputs: 5 digital, 5 analog for the pots and 4 digital for the buttons (iirc).

    The problem then moves into the software, in that the more time spent reading inputs, the less time available to send midi, so you will encounter latency... I have no clue when that will become a factor (as in how many inputs), but with my current prototype it reads all the inputs (about 27) 50,000 times per second... I have a feeling I have a little headroom before I have to worry

    I would like to find some sort of information as to how many messages per second is required for "zero latency"...

    Quote Originally Posted by safefire View Post
    As well, since you're drawing up things in eagle, I assume you've put some work into designing the PCBs as well?
    Yeah, I've done a few



    Here's a quick writeup I did a while back: http://arduino.cc/forum/index.php/topic,5650.0.html

    Quote Originally Posted by safefire View Post
    Your workflow looks very similar to mine, too. I'm quite well versed in drawing up schematics and plans for controllers, cases and parts, if you'd like some help getting things laid out nice and tidy, give me a shout

    Keep up the good work
    Well here is the current state of the prototype. The channels, fx, and transport sections are complete, still have to take care of the loops and globals, then fit as many more controls as space allows...

    I invite criticism and suggestions to the layout, it's a fluid work in process so any input is always appreciated

    btw, it is currently 18" x 13" (and I have already decided to move the xfader down a half inch or so)


  10. #30

Page 3 of 16 FirstFirst 123456713 ... LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •