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

Thread: stuck with polyphony (last note priority)

  1. #1
    Senior Member
    Join Date
    Dec 2018
    Posts
    129

    stuck with polyphony (last note priority)

    Hello,

    I try to make a simple polyphonic synth. I would like to have 5 voices with last note priority. I have been fighting all day with the "last note priority" feature. I would really appreciate if someone could indicate me a method or approach. I prefer not posting my code, because it is a mess and it doesn't work. I think I need a new fresh start.

    Emmanuel

  2. #2
    Senior Member
    Join Date
    Apr 2019
    Posts
    132
    Hello Emmanuel. Yes, handing voices to in-coming notes is something that took me a while to implement on TSynth until I just sat down and wrote a series of operations based on what should happen. It isn't the best way perhaps, but it's reliably worked. You need to record when voices are assigned to notes, so that in-coming notes can be assigned to either 'free', no longer active voices or active voices that were assigned at the oldest time. This is from my code:

    Code:
    #define NO_OF_VOICES 12
    
    long earliestTime = millis(); //For voice allocation - initialise to now
    
    struct VoiceAndNote {
      uint32_t note;
      long timeOn;
      uint32_t voiceOn;//just a boolean 0 off / 1 on
    };
    
    struct VoiceAndNote voices[NO_OF_VOICES] = {{ -1, 0, 0}, { -1, 0, 0}, { -1, 0, 0}, { -1, 0, 0}, { -1, 0, 0}, { -1, 0, 0}, { -1, 0, 0}, { -1, 0, 0}, { -1, 0, 0}, { -1, 0, 0}, { -1, 0, 0}, { -1, 0, 0}};
    
    //This returns the number of the voice you are assigning the note to
    // note = -1 means you want to be assigned a voice for note on
    // note= 0 - 127 is returning the voice that was previously assigned to that note, for note off
    //voices are numbered from 1 not 0
    int getVoiceNo(int note) {
      uint32_t voiceToReturn = -1;      //Initialise
      earliestTime = millis(); //Initialise to now
      if (note == -1) {
        //NoteOn() - Get the oldest free voice (recent voices may be still on release stage)
        for (int i = 0; i < NO_OF_VOICES; i++) {
          if (voices[i].voiceOn == 0) {
            if (voices[i].timeOn < earliestTime) {
              earliestTime = voices[i].timeOn;
              voiceToReturn = i;
            }
          }
        }
        if (voiceToReturn == -1) {
          //No free voices, need to steal oldest sounding voice
          earliestTime = millis(); //Reinitialise
          for (int i = 0; i < NO_OF_VOICES; i++) {
            if (voices[i].timeOn < earliestTime) {
              earliestTime = voices[i].timeOn;
              voiceToReturn = i;
            }
          }
        }
        return voiceToReturn + 1;
      } else {
        //NoteOff() - Get voice number from note
        for (int i = 0; i < NO_OF_VOICES; i++) {
          if (voices[i].note == note && voices[i].voiceOn == 1) {
            return i + 1;
          }
        }
      }
      //Shouldn't get here, return voice 1
      return 1;
    }
    
    //Then set the voices[].note in the code where the voice is sounded:
     voices[0].note = note;
      voices[0].timeOn = millis();
      voices[0].voiceOn= 1;
    
    //And set this for note off
      voices[0].voiceOn= 0;
    This is partly why synths like the SCI Prophets were expensive, they had a Z80 CPU to control among other things the distribution of voices to notes.
    Last edited by UHF; 01-01-2021 at 05:18 AM.

  3. #3
    Senior Member
    Join Date
    Jul 2020
    Posts
    927
    Here's one approach:

    First a filter layer to generate extra noteOff and noteOn messages/calls to ensure the live note count is <= 5.

    Secondly a standard mapping from notes to oscillators which never has to deal with more than 5 notes.

    I suspect you want a different ADSR setting for when a note gets restarted due to a later note going away and
    freeing up an oscillator.

    There's an issue with handover of an oscillator from one note to a new one - the release phase has to be
    expedited to allow the new note to start in a timely fashion, but not so fast that there's an audible click.

  4. #4
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    276
    You can use UHF:s approach but instead of using time on you can just simply count up a var each time a new note is played and use that as the ref. for first note "replace", using a unsigned long (32bit) makes it possible to play 5*10 notes each second in ~2.7years straight without need to consider for overflow.

  5. #5
    Junior Member
    Join Date
    Sep 2018
    Posts
    16
    Quote Originally Posted by manicksan View Post
    You can use UHF:s approach but instead of using time on you can just simply count up a var each time a new note is played and use that as the ref. for first note "replace", using a unsigned long (32bit) makes it possible to play 5*10 notes each second in ~2.7years straight without need to consider for overflow.
    A simple approach is to create a circular buffer of pointers to voices. Increment a pointer into that buffer when starting a new note. Roll over when you've hit the number of voices available. This doesn't take duration into account, but you could alternately add a sort based on how many milliseconds remain, or percentage done for each note, relative volume, etc...

  6. #6
    Senior Member
    Join Date
    Dec 2019
    Posts
    134
    no need to reinvent the wheel. https://forum.pjrc.com/threads/59092...onic-expansion The main midi synth example included with the examples can easily be expanded. I currently run 10 key polyphony with 16 voice unison no problem with a slightly modified version of the post I reference.

  7. #7
    Senior Member
    Join Date
    Dec 2019
    Posts
    134
    If you get stuck expanding the referenced post, let me know and I'll provide some base code. It's a good mental exercise, however, and I recommend giving it a try.

  8. #8
    Senior Member
    Join Date
    Dec 2018
    Posts
    129
    Thank you all.

    I finally succeed in making an 8 voices synth, following examples and ideas of this thread.
    Emmanuel

Posting Permissions

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