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

Thread: MIDI all notes off

  1. #1

    MIDI all notes off

    I have built a sequencer, but I have trouble making the all notes off message work as intended when it stops. What happens is that i get hanging notes after the sequencer stops. Not sure where I fail.

    The gist of my code is that whenever I stop my sequencer, the allChannelsAllNotesOff() function is called. I've triple checked the midi command value for the all notes off message... All the other messages are working as expected. Happy if someone could look at my code!

    Code:
    MIDI.cpp
    
    void MIDI::noteOff(const uint8_t voiceNumber) {
        using namespace constants;
    
        Serial1.write(MIDInoteOff + voiceNumber);
        Serial1.write(m_previousMIDINote[voiceNumber]);
        Serial1.write(0);
    }
    
    void MIDI::allNotesOff(const uint8_t voiceNumber) {
        using namespace constants;
    
        Serial1.write(MIDIchannel + voiceNumber);  // Channel CC message
        Serial1.write(MIDIallNotesOff);
        Serial1.write(0);
    }
    
    void MIDI::allChannelsAllNotesOff() {
        using namespace constants;
    
        for (uint8_t voiceNumber = voice1; voiceNumber <= voice4; ++voiceNumber) {
            allNotesOff(voiceNumber);
        }
    }
    
    
    Constants.h
    
    constexpr uint8_t MIDIstart = 0xFA;        // 250
    constexpr uint8_t MIDIstop = 0xFC;         // 252
    constexpr uint8_t MIDInoteOn = 0x90;       // 144
    constexpr uint8_t MIDInoteOff = 0x80;      // 128
    constexpr uint8_t MIDIchannel = 0xB0;      // 176
    constexpr uint8_t MIDIallNotesOff = 0x7B;  // 123
    
    enum voiceNumbers {
        voice1,
        voice2,
        voice3,
        voice4,
        allVoices
    };

  2. #2
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    1,248
    The sequencer output goes to a synthesizer, correct?
    Could it be that the synthesizer does not support the Channel Mode Message: All Notes Off?
    (your partial code looks OK to me)

    Paul

  3. #3
    Thanks for your feedback. Yes, synthesizer.

    I checked the manual for one of the synths I'm using, and it does in fact confirm that there isn't any support for all notes off messages. For another one of my synths, it's allegedly accepting all notes off messages according to other users. I still get hanging notes, so I think I'll try contacting their support next.

  4. #4
    Senior Member
    Join Date
    Aug 2019
    Location
    Melbourne Australia
    Posts
    378
    In this bit
    Code:
    for (uint8_t voiceNumber = voice1; voiceNumber <= voice4; ++voiceNumber) {
            allNotesOff(voiceNumber);
        }
    The synth may not have completed silencing all notes in voice1 before allNotesOff(voice2) is sent so a delay may be worth playing with.

    Ears pricked up after wrestling code for a sequencer for days, just got it working so posting the guts as food for thought.
    Code:
    void Seq2(int trkIndex) {
      // Called by a Timer
      // Prepare the sequence
      if (TrackData[trkIndex].IsRunning != false) {
        if (TrackData[trkIndex].NoteSent == false) {
          TrackData[trkIndex].NoteSent = true; // so we don't come back here if the seq is started
          if (TrackNoteData[trkIndex][CurrStep[trkIndex]].Active == true) { // the step might have been muted
            // this chooses per Track vel or per step vel
            if (TrackData[trkIndex].VelByTrack == true) {
              byte vel = TrackData[trkIndex].Vel;
              MIDI.sendNoteOn(TrackNoteData[trkIndex][CurrStep[trkIndex]].NoteNum, vel, TrackData[trkIndex].MidiChannel);
            }
            else if (TrackData[trkIndex].VelByTrack != true) {
              byte vel = TrackNoteData[trkIndex][CurrStep[trkIndex]].NoteVel;
              MIDI.sendNoteOn(TrackNoteData[trkIndex][CurrStep[trkIndex]].NoteNum, vel, TrackData[trkIndex].MidiChannel);
            }
          }
        }
        TrackData[trkIndex].TickCount++;
        if (TrackData[trkIndex].TickCount == TrackData[trkIndex].NoteLength) {
          // yet to add per Track  or per Step Note Length 
          if (TrackNoteData[trkIndex][CurrStep[trkIndex]].Active == true) { // the step might have been muted
            MIDI.sendNoteOff(TrackNoteData[trkIndex][CurrStep[trkIndex]].NoteNum, 0, TrackData[trkIndex].MidiChannel);
          }
        }
      }
      if (TrackData[trkIndex].TickCount >= 95) { // thinking of 96 ticks per note
        TrackData[trkIndex].NoteSent = false;
        TrackData[trkIndex].TickCount = 0;
        StepCount[trkIndex]++;
        CurrStep[trkIndex] = StepCount[trkIndex];
        //CurrStep and StepCount have same value here, playing around with FirstStep, LastStep
        //and variable Start step. The goal is to be able to create a base to implement Euclidean
        //or "normal" linear sequences like eg. Beatstep Pro
    
        // Now, this bit makes us deaf to the Halt command until the current Step is complete
        if (TrackData[trkIndex].Halt == true) {
          TrackData[trkIndex].IsRunning = false;
        }
        if (StepCount[trkIndex] > TrackData[trkIndex].LastStep) {
          // Now, the Sequence has completed then repeat
          TrackData[trkIndex].TickCount = 0;
          StepCount[trkIndex] = TrackData[trkIndex].FirstStep;
          CurrStep[trkIndex] = StepCount[trkIndex];
        }
      }
    }

  5. #5
    Quote Originally Posted by MatrixRat View Post
    The synth may not have completed silencing all notes in voice1 before allNotesOff(voice2) is sent so a delay may be worth playing with.
    Interesting suggestion! I tried just now, but unfortunately there was no difference. As far as I understand the Serial.port buffers the data, and the transmit speed is set to midi standard.

  6. #6
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,135
    From the MIDI 1.0 spec (my emphasis):

    All Notes Off (123) is a mode message which provides an efficient method of turning off all voices turned
    on via MIDI. While this message is useful for some applications, there is no requirement that a receiver
    recognize it. Since recognition of All Notes Off is not required of the receiver, all notes should first be
    turned off by transmitting individual Note-Off messages prior to sending an All Notes Off.
    So it is efficient if implemented but the safe and secure method, assuming you have a list of notes turned on, is (sadly) sending all the corresponding Note-Off messages.

    The specification wording is classic post-hoc standardization:

    Receivers should ignore an All Notes Off message while Omni is on (Modes 1 & 2). For example, if a
    receiver gets an All Notes Off from a sequencer that inserts such messages whenever all keys are
    released on a track, and two tracks were recorded on such a sequencer (even on different MIDI
    channels), the All Notes Off message would cut off sustaining notes recorded on the other track.

    While MIDI devices should be able to respond to the All Notes Off message, an All Notes Off message
    should not be sent periodically as part of normal operation. This message should only be used to indicate
    that the entire MIDI system is "at rest" (i.e. when a sequence has stopped). However, a receiver should
    respond to an All Notes Off (unless Omni is on) whenever it is received, even when the system is not "at
    rest".

  7. #7
    I did not know this, and this solved the problem. Thank you!

    It seems that sending individual note off messages prior to sending the all notes off command makes the latter completely redundant, doesn't it?

  8. #8
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,135
    Yes, it does. This has the feel of "great new idea, nice in theory", spoiled by backwards compatibility and divergent implementations in practice.

    Also the "not in OMNI mode" caveat at least has some justification.

Posting Permissions

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