Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 16 of 16

Thread: What USB and Port settings for Hardware MIDI on LC?

  1. #1
    Junior Member
    Join Date
    Oct 2020
    Posts
    11

    What USB and Port settings for Hardware MIDI on LC?

    Using tutorial provided here (https://www.pjrc.com/teensy/td_libs_MIDI.html), I'm unable to receive hardware MIDI input from a hardware sequencer. Any guidance is greatly appreciated!

    I am a new coder and new to Teensy. Was successful with a MIDI monitor sketch using UNO and a different sketch and basic hardware MIDI I/O circuit but due to UNO limitations, the sketch stopped working at higher BPMs, which is why I moved to Teensy.

    Trying to determine what I am missing here? Do I need additional usbMIDI commands included in the sketch for the serial output?

    I am also unclear what USB and Port settings for Hardware MIDI on my Teensy-LC?

    I've followed the schematic here: https://www.pjrc.com/teensy/td_libs_MIDI_sch_t3.png
    Click image for larger version. 

Name:	td_libs_MIDI_sch_t3.png 
Views:	13 
Size:	4.9 KB 
ID:	21955

    Using this sketch:
    Code:
    /* MIDI Input Test - for use with Teensy or boards where Serial is separate from MIDI
     * As MIDI messages arrive, they are printed to the Arduino Serial Monitor.
     *
     * Where MIDI is on "Serial", eg Arduino Duemilanove or Arduino Uno, this does not work!
     *
     * This example code is released into the public domain.
     */
     
    #include <MIDI.h>
    
    MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
    
    void setup() {
      MIDI.begin(MIDI_CHANNEL_OMNI);
      Serial.begin(57600);
      Serial.println("MIDI Input Test");
    }
    
    unsigned long t=0;
    
    void loop() {
      int type, note, velocity, channel, d1, d2;
      if (MIDI.read()) {                    // Is there a MIDI message incoming ?
        byte type = MIDI.getType();
        switch (type) {
          case midi::NoteOn:
            note = MIDI.getData1();
            velocity = MIDI.getData2();
            channel = MIDI.getChannel();
            if (velocity > 0) {
              Serial.println(String("Note On:  ch=") + channel + ", note=" + note + ", velocity=" + velocity);
            } else {
              Serial.println(String("Note Off: ch=") + channel + ", note=" + note);
            }
            break;
          case midi::NoteOff:
            note = MIDI.getData1();
            velocity = MIDI.getData2();
            channel = MIDI.getChannel();
            Serial.println(String("Note Off: ch=") + channel + ", note=" + note + ", velocity=" + velocity);
            break;
          default:
            d1 = MIDI.getData1();
            d2 = MIDI.getData2();
            Serial.println(String("Message, type=") + type + ", data = " + d1 + " " + d2);
        }
        t = millis();
      }
      if (millis() - t > 10000) {
        t += 10000;
        Serial.println("(inactivity)");
      }
    }
    Here's the photos of my MIDI I/O circuit built based on the PJRC schematic (pins are correctly connected for serial 1 & power but camera angle is not):
    Click image for larger version. 

Name:	IMG_5401.jpg 
Views:	14 
Size:	96.3 KB 
ID:	21956
    Click image for larger version. 

Name:	IMG_5404.jpg 
Views:	10 
Size:	103.6 KB 
ID:	21957
    Click image for larger version. 

Name:	IMG_5405.jpg 
Views:	7 
Size:	87.7 KB 
ID:	21958
    Click image for larger version. 

Name:	IMG_5406.jpg 
Views:	14 
Size:	113.4 KB 
ID:	21959

    MIDI out from sequencer to Board Hardware Din input and Teensy-LC USB plugged into computer USB and is recognized:
    Click image for larger version. 

Name:	Screen Shot 2020-10-03 at 12.17.18 PM.png 
Views:	14 
Size:	148.1 KB 
ID:	21960

  2. #2
    Junior Member
    Join Date
    Oct 2020
    Posts
    11
    Hi forum admins - is there any way you can move my post to the audio forums? Perhaps I could receive some guidance there? Apologies if I posted in the wrong place...

  3. #3
    Junior Member
    Join Date
    Oct 2020
    Posts
    11
    Is there anyone that can provide some insight here? Any help would be greatly appreciated.

  4. #4
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,371
    I've looked that breadboard over several times and keep thinking I see the problem but then it's just me...

    The Tx line isn't clear (at the resistor) but you say that's working and I can't see anything with the Rx side.

    I'm not an EE and not great at spotting breadboard error but since no one else was answering i thought maybe it was worth saying the problem doesn't look obvious to me.

    Reversed polarity at the MIDI socket is a common problem but it looks to me you have that correct.

    I didn't read the resistor codes, are you sure about them? (Maybe meter test them to make sure they're not way off but none of the values are crucial so it would have to be a significant difference to cause the circuit to fail -- but I don't trust my code reading so I often meter test resistors to see i have the order of magnitude correct.)



    Sorry I can't help more than that.

  5. #5
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,371
    Oh... are you getting the setup message on the serial monitor?

    FYI - You don't want to select MIDI for USB type as you are just sending serial to the computer for this sketch.

  6. #6
    Senior Member
    Join Date
    Aug 2019
    Location
    Melbourne Australia
    Posts
    162
    Oops, sorry I missed this thread. If you want the Teensy to work as a Midi - usbMidi interface this might be a useful starting point:-
    Code:
    /* Create a "class compliant " USB to 1 MIDI IN and 1 MIDI OUT interface.
    
       MIDI receive (6N138 optocoupler) input circuit and series resistor
       outputs need to be connected to Serial1
    
       You must select MIDI from the "Tools > USB Type" menu
    
       This example code is in the public domain.
    */
    
    #include <MIDI.h>
    
    // Create the Serial MIDI ports
    MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI1);
    
    // A variable to know how long the LED has been turned on
    elapsedMillis ledOnMillis;
    
    
    void setup() {
      Serial.begin(115200);
      pinMode(13, OUTPUT); // LED pin
      digitalWrite(13, LOW);
      MIDI1.begin(MIDI_CHANNEL_OMNI);
     
    }
    
    
    void loop() {
      bool activity = false;
    
      if (MIDI1.read()) {
        // get a MIDI IN1 (Serial) message
        byte type = MIDI1.getType();
        byte channel = MIDI1.getChannel();
        byte data1 = MIDI1.getData1();
        byte data2 = MIDI1.getData2();
    
        // forward the message to USB MIDI virtual cable #0
        if (type != midi::SystemExclusive) {
          // Normal messages, simply give the data to the usbMIDI.send()
          usbMIDI.send(type, data1, data2, channel, 0);
        } else {
          // SysEx messages are special.  The message length is given in data1 & data2
          unsigned int SysExLength = data1 + data2 * 256;
          usbMIDI.sendSysEx(SysExLength, MIDI1.getSysExArray(), true, 0);
        }
        activity = true;
      }
    
     
    
      if (usbMIDI.read()) {
        // get the USB MIDI message, defined by these 5 numbers (except SysEX)
        byte type = usbMIDI.getType();
        byte channel = usbMIDI.getChannel();
        byte data1 = usbMIDI.getData1();
        byte data2 = usbMIDI.getData2();
        byte cable = usbMIDI.getCable();
    
        // forward this message to 1 of the 3 Serial MIDI OUT ports
        if (type != usbMIDI.SystemExclusive) {
          // Normal messages, first we must convert usbMIDI's type (an ordinary
          // byte) to the MIDI library's special MidiType.
          midi::MidiType mtype = (midi::MidiType)type;
    
          // Then simply give the data to the MIDI library send()
          switch (cable) {
            case 0:
              MIDI1.send(mtype, data1, data2, channel);
              break;
          
          }
    
        } else {
          // SysEx messages are special.  The message length is given in data1 & data2
          unsigned int SysExLength = data1 + data2 * 256;
          switch (cable) {
            case 0:
              MIDI1.sendSysEx(SysExLength, usbMIDI.getSysExArray(), true);
              break;
        
          }
        }
        activity = true;
      }
    
      // blink the LED when any activity has happened
      if (activity) {
        digitalWriteFast(13, HIGH); // LED on
        ledOnMillis = 0;
      }
      if (ledOnMillis > 15) {
        digitalWriteFast(13, LOW);  // LED off
      }
    
    }
    Hope this helps.

  7. #7
    Junior Member
    Join Date
    Oct 2020
    Posts
    11
    Quote Originally Posted by oddson View Post
    I've looked that breadboard over several times and keep thinking I see the problem but then it's just me...

    The Tx line isn't clear (at the resistor) but you say that's working and I can't see anything with the Rx side.

    I'm not an EE and not great at spotting breadboard error but since no one else was answering i thought maybe it was worth saying the problem doesn't look obvious to me.

    Reversed polarity at the MIDI socket is a common problem but it looks to me you have that correct.

    I didn't read the resistor codes, are you sure about them? (Maybe meter test them to make sure they're not way off but none of the values are crucial so it would have to be a significant difference to cause the circuit to fail -- but I don't trust my code reading so I often meter test resistors to see i have the order of magnitude correct.)



    Sorry I can't help more than that.

    Thanks so much for looking over the breadboard. I took everything down and double checked the connections (reverse polarity, resistor values, wire continuity) so I think I am all set there now. The extra sets of eyes are always a help!

    Quote Originally Posted by oddson View Post
    Oh... are you getting the setup message on the serial monitor?

    FYI - You don't want to select MIDI for USB type as you are just sending serial to the computer for this sketch.
    Thanks for confirming the USB type as "serial". To clarify: I want to be able to monitor everything (incoming external MIDI input) over hardware serial. Initially want to see it print out over serial monitor.

    Quote Originally Posted by MatrixRat View Post
    Oops, sorry I missed this thread. If you want the Teensy to work as a Midi - usbMidi interface this might be a useful starting point:-
    Code:
    /* Create a "class compliant " USB to 1 MIDI IN and 1 MIDI OUT interface.
    
       MIDI receive (6N138 optocoupler) input circuit and series resistor
       outputs need to be connected to Serial1
    
       You must select MIDI from the "Tools > USB Type" menu
    
       This example code is in the public domain.
    */
    
    #include <MIDI.h>
    
    // Create the Serial MIDI ports
    MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI1);
    
    // A variable to know how long the LED has been turned on
    elapsedMillis ledOnMillis;
    
    
    void setup() {
      Serial.begin(115200);
      pinMode(13, OUTPUT); // LED pin
      digitalWrite(13, LOW);
      MIDI1.begin(MIDI_CHANNEL_OMNI);
     
    }
    
    
    void loop() {
      bool activity = false;
    
      if (MIDI1.read()) {
        // get a MIDI IN1 (Serial) message
        byte type = MIDI1.getType();
        byte channel = MIDI1.getChannel();
        byte data1 = MIDI1.getData1();
        byte data2 = MIDI1.getData2();
    
        // forward the message to USB MIDI virtual cable #0
        if (type != midi::SystemExclusive) {
          // Normal messages, simply give the data to the usbMIDI.send()
          usbMIDI.send(type, data1, data2, channel, 0);
        } else {
          // SysEx messages are special.  The message length is given in data1 & data2
          unsigned int SysExLength = data1 + data2 * 256;
          usbMIDI.sendSysEx(SysExLength, MIDI1.getSysExArray(), true, 0);
        }
        activity = true;
      }
    
     
    
      if (usbMIDI.read()) {
        // get the USB MIDI message, defined by these 5 numbers (except SysEX)
        byte type = usbMIDI.getType();
        byte channel = usbMIDI.getChannel();
        byte data1 = usbMIDI.getData1();
        byte data2 = usbMIDI.getData2();
        byte cable = usbMIDI.getCable();
    
        // forward this message to 1 of the 3 Serial MIDI OUT ports
        if (type != usbMIDI.SystemExclusive) {
          // Normal messages, first we must convert usbMIDI's type (an ordinary
          // byte) to the MIDI library's special MidiType.
          midi::MidiType mtype = (midi::MidiType)type;
    
          // Then simply give the data to the MIDI library send()
          switch (cable) {
            case 0:
              MIDI1.send(mtype, data1, data2, channel);
              break;
          
          }
    
        } else {
          // SysEx messages are special.  The message length is given in data1 & data2
          unsigned int SysExLength = data1 + data2 * 256;
          switch (cable) {
            case 0:
              MIDI1.sendSysEx(SysExLength, usbMIDI.getSysExArray(), true);
              break;
        
          }
        }
        activity = true;
      }
    
      // blink the LED when any activity has happened
      if (activity) {
        digitalWriteFast(13, HIGH); // LED on
        ledOnMillis = 0;
      }
      if (ledOnMillis > 15) {
        digitalWriteFast(13, LOW);  // LED off
      }
    
    }
    Hope this helps.
    Thanks so much for taking the time to share this code for the teensy work as a Midi - usbMidi interface and no worries on the late reply!

    However, my goal is to have a hardware MIDI I/O interface that acts as a MIDI data monitor. The MIDI Out of my breadboard connects to a USB MIDI interface so I can connect to a software sound source in a DAW.

    This is a good example of what I am after: https://github.com/sparkfun/MIDI_Shi...DI-sniffer.ino
    However, it utilizes software serial.

    When I built a hardware MIDI I/O interface and used an UNO with this sketch, it worked - to a point - but then at higher BPMs from the incoming MIDI input, it would stop working: while the serial monitor was reading all the MIDI data, the output would get "stuck". Notes sent from the MIDI input sequencer would get stuck "on", and after I stopped the sequencer, I'd hear a distinct echo/ feedback noise coming from the receiving sound source and have to reset it.

    This is why I am trying to set things up on a Teensy LC to have access to three hardware serial ports independent of the USB line. This is also where I am getting confused about what USB and port settings I need for a Hardware MIDI I/O interface that also monitors MIDI data. I imagine it would be possible to "port" over the referenced sketch and omit software serial altogether?

  8. #8
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,976
    Definitely don't use SoftwareSerial. It barely even works for just 1 instance, and when it does it hogs up the CPU which tends to make everything else perform quite badly.

    From everything you've described, it sounds like you want 3 MIDI library instances using the 3 hardware serial ports, and then just use ordinary Serial (which is native USB serial on all Teensy boards) to talk to your PC running software like the Arduino Serial Monitor. If you just want to "see" the MIDI messages as readable text on your PC (but not as actual USB MIDI communication), that way would make the most sense. In Arduino, make sure Tools > USB Type is set to "Serial".


    I imagine it would be possible to "port" over the referenced sketch and omit software serial altogether?
    Yes. That Sparkfun code looks like it ought to work if you just delete the SoftwareSerial and change the MIDI_CREATE_INSTANCE to this:

    Code:
    MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
    On Teensy LC, the SoftwareSerial library also "knows" how to use real serial if you use the pin numbers of a real hardware serial port. So you might be able to get that Sparkfun program running on Teensy LC if you just change the pin numbers, like this:

    Code:
    SoftwareSerial SoftSerial(0, 1);

  9. #9
    Junior Member
    Join Date
    Oct 2020
    Posts
    11
    Quote Originally Posted by PaulStoffregen View Post
    Definitely don't use SoftwareSerial. It barely even works for just 1 instance, and when it does it hogs up the CPU which tends to make everything else perform quite badly.

    From everything you've described, it sounds like you want 3 MIDI library instances using the 3 hardware serial ports, and then just use ordinary Serial (which is native USB serial on all Teensy boards) to talk to your PC running software like the Arduino Serial Monitor. If you just want to "see" the MIDI messages as readable text on your PC (but not as actual USB MIDI communication), that way would make the most sense. In Arduino, make sure Tools > USB Type is set to "Serial".




    Yes. That Sparkfun code looks like it ought to work if you just delete the SoftwareSerial and change the MIDI_CREATE_INSTANCE to this:

    Code:
    MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);
    On Teensy LC, the SoftwareSerial library also "knows" how to use real serial if you use the pin numbers of a real hardware serial port. So you might be able to get that Sparkfun program running on Teensy LC if you just change the pin numbers, like this:

    Code:
    SoftwareSerial SoftSerial(0, 1);
    Ok, fantastic, Paul! This is super helpful and thanks for all the clarification on the USB and port settings and pointers on how to utilize the sparkfun sketch I referenced with the Teensy LC. I will give it a try with and without the SoftwareSerial library to see how it performs.

  10. #10
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,976
    If you expand this to all 3 hardware serial ports, and if all 3 could be expected to have sustained running at nearly max MIDI bandwidth, using Teensy LC you might need to be mindful of how much formatting and other work you're doing to convert the raw MIDI messages into human readable messages. As long as you keep the message formatting simple, I'm pretty sure Teensy LC can keep up and the native USB should be plenty fast enough.

    But if you do more complex message formatting on the Teensy, you might need to step up to Teensy 3.2 or 4.0. Teensy LC is significantly faster than Arduino Uno, but nowhere nearly as powerful as Teensy 3.2 or 4.0. Many benchmark tests have shown Teensy LC can keep up with full USB bandwidth only when the code is quite simple. The faster models are able to do so much more without impacting ability to keep up with full USB bandwidth.

    Keep the message printing simple if using Teensy LC and all 3 ports, and if you expect all 3 to have sustained periods of heavy MIDI bandwidth usage.

  11. #11
    Junior Member
    Join Date
    Oct 2020
    Posts
    11
    Quote Originally Posted by PaulStoffregen View Post
    If you expand this to all 3 hardware serial ports, and if all 3 could be expected to have sustained running at nearly max MIDI bandwidth, using Teensy LC you might need to be mindful of how much formatting and other work you're doing to convert the raw MIDI messages into human readable messages. As long as you keep the message formatting simple, I'm pretty sure Teensy LC can keep up and the native USB should be plenty fast enough.

    But if you do more complex message formatting on the Teensy, you might need to step up to Teensy 3.2 or 4.0. Teensy LC is significantly faster than Arduino Uno, but nowhere nearly as powerful as Teensy 3.2 or 4.0. Many benchmark tests have shown Teensy LC can keep up with full USB bandwidth only when the code is quite simple. The faster models are able to do so much more without impacting ability to keep up with full USB bandwidth.

    Keep the message printing simple if using Teensy LC and all 3 ports, and if you expect all 3 to have sustained periods of heavy MIDI bandwidth usage.
    That is great to know that all 3 hardware serials could potentially be monitored with the caveats you mention on the LC. For now, I plan to use one hardware serial port with minimal message formatting so I should be good to go.

  12. #12
    Junior Member
    Join Date
    Oct 2020
    Posts
    11
    I wanted to report back that the sparkfun MIDI sniffer sketch works flawlessly using both methods that Paul outlined above. Thanks to everyone who lent a helping hand!

    Now on to converting those MIDI clock ticks to BPM values and note #s to note name =)

  13. #13
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,371
    ...so what was wrong with your initial attempts?

    Glad to see your having success now.


    Now on to converting those MIDI clock ticks to BPM values and note #s to note name =)
    Hints:
    Modulo division by 12 on MIDI notes gives you an zero-based array index for note names from C to B

    e.g.
    noteName = names[note%12]

    You can even have one array for sharp names and one for flats and then de-reference the name based on whether the key sig. has flats or not.

    I have problems with BPM conversions every time... but the crucial thing the inversion from a duration to a rate:

    mSec/beat = x
    Sec/beat = 1/1000*x
    Min/beat = 1/60*1/1000*x
    BPM = 60000 / (ms/Beat)

    I.e. - Invert the duration and scale by the time factor.

  14. #14
    Junior Member
    Join Date
    Oct 2020
    Posts
    11
    ...so what was wrong with your initial attempts?

    Glad to see your having success now.
    I am not entirely sure but I re-did the breadboard several times. All the components (resistors, diode, opto) were all ok but I think it was something to have to do with ground. I forgot that the DIN connectors have two front metal pins that were also on the ground line. Perhaps that was the cause. I took that out of the re-factoring and the circuit worked.

    Code:
    Hints:
    Modulo division by 12 on MIDI notes gives you an zero-based array index for note names from C to B
    
    e.g.
    noteName = names[note%12]
    
    You can even have one array for sharp names and one for flats and then de-reference the name based on whether the key sig. has flats or not.
    
    I have problems with BPM conversions every time... but the crucial thing the inversion from a duration to a rate:
    
    mSec/beat = x
    Sec/beat = 1/1000*x
    Min/beat = 1/60*1/1000*x
    BPM = 60000 / (ms/Beat)
    
    I.e. - Invert the duration and scale by the time factor.
    Thank you so much for these hints - in researching the note names I've found some examples that are in line with your hint but I am not entirely sure how to incorporate them into my sketch just yet. In the MIDI sniffer sketch I am using, there are two switch cases for NoteOff and NoteOn that return the Note #:

    Code:
    case midi::NoteOff :
              {
                Serial.print("NoteOff, chan: ");
                Serial.print(MIDI.getChannel());
                Serial.print(" Note#: ");
                Serial.print(MIDI.getData1());
                Serial.print(" Vel#: ");
                Serial.println(MIDI.getData2());
              }
              break;
            case midi::NoteOn :
              {
                uint8_t vel;
    
                Serial.print("NoteOn, chan: ");
                Serial.print(MIDI.getChannel());
                Serial.print(" Note#: ");
                Serial.print(MIDI.getData1());
                Serial.print(" Vel#: ");
                vel = MIDI.getData2();
                Serial.print(vel);
                if (vel == 0)
                {
                  Serial.print(" *Implied off*");
                }
                Serial.println();
              }
              break;
    If I understand correctly:

    Code:
    MIDI.getData1();
    MIDI.getData2();
    are what return the 2 data bytes of the received MIDI message? So I need to use the MIDI note# data pulled from MIDI.getData1(?) and take it a step further. This seems similar to your method:

    Code:
    // https://forum.pjrc.com/threads/43924-convert-midi-note-to-note-name
    
    String noteName[] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
    int MidiNoteName;
    int noteOctave;
    
    void setup() {
    Serial.begin(9600);
    }
    
    void loop() {
      Serial.println("Start");
      delay(100);
      int i;
      for (i=0; i<=127; i++) {
        noteOctave = i/12;
        MidiNoteName = i%12;
        Serial.println("Note: "+String(i)+" "+String(noteName[MidiNoteName])+" "+String(noteName[MidiNoteName])+String(noteOctave));
        delay(50);
      }
      delay(200);
    }
    With regards to the BPM conversions, the MIDI sniffer sketch I am using as a guide uses the MsTimer2 library: https://github.com/sparkfun/MIDI_Shi...DI-sniffer.ino

    To calculate the BPM as you describe, would I need to use MIDI.setHandleClock(handleClock) in addition to MsTimer library or would that be redundant? If I understand correctly these switch cases are displaying the clock byte values:

    Code:
    case midi::Clock :
              {
                clock_ticks++;
    
                Serial.print("Clock ");
                Serial.println(clock_ticks);
              }
              break;
            case midi::Start :
              {
                clock_ticks = 0;
                Serial.println("Starting");
              }
              break;
            case midi::Stop :
              {
                old_clock_ticks = clock_ticks;
                Serial.println("Stopping");
              }
              break;

  15. #15
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,371
    Yes... D1, obtained with MIDI.getData1(), is the note value that you take mod-12 to get the index.

    On the clock thing... some details in this thread: https://forum.pjrc.com/threads/58366...-for-tempo-LED

  16. #16
    Junior Member
    Join Date
    Oct 2020
    Posts
    11
    Yes... D1, obtained with MIDI.getData1(), is the note value that you take mod-12 to get the index.
    Wonderful - I've got that sorted now - thank you!

    On the clock thing... some details in this thread: https://forum.pjrc.com/threads/58366...-for-tempo-LED
    Again thank you for pointing me here - will take a look and report back when I have made some progress.

Posting Permissions

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