Arduino PSS-680 Synth Editor- Part 2

Following on from Part 1, this post looks at combining several of my previous projects to allow me to control the synth of a PSS-680 from a set of potentiometers.

  • Part 1 – Goes into the detail of the MIDI implementation for the PSS-680 and how to handle the SysEx messages from an Arduino.

Warning! I strongly recommend using old or second hand equipment for your experiments.  I am not responsible for any damage to expensive instruments!

These are the key Arduino tutorials for the main concepts used in this project:

If you are new to Arduino, see the Getting Started pages.

Parts list

The Circuit

The aim is to use a bank of potentiometers to control a range of synth parameters for the PSS-680. There are several options:

I’ve chosen to use my Analog IO Board PCB in multiplexer mode, using a 74HC4051 or CD4051, 8-channel analog multiplexer. I’m also using my Simple MIDI Serial Monitor – Part 3.

The Code

This is using the core code from part 1 but now supports the editing of more parameters and potentiometer control. The multiplexer code is explained here: Arduino MIDI Mux Step Sequencer.

Once again, a voice dump is required before editing can take place, so the workflow is as follows:

  1. Select the voice to use as a basis for the editing.
  2. Store it in Bank 1.
  3. Send a memory dump to the Arduino.
  4. Adjust the synth paramters as required.
  5. If any parameters are adjusted from the PSS-680’s panel then perform another memory dump back to the Arduino.

As the only communications between the Arduino and the PSS-680 is via 72-byte SysEx messages, I’ve taken particular care in the code to only update the synth when the paramters have really changed. Most of this is taken care of in the following function:

int pots[NUM_POTS];
bool updatePotReading (int pot, int reading) {
  if (pots[pot] == reading) {
    return false;
  }
  pots[pot] = reading;
  return true;
}

bool updateSynthParams(int pot, unsigned reading) {
  switch (pot) {
    case 0:
      if (updatePotReading(pot, reading>>8)) {
        setSinTbl (1, reading>>8);
        return true;
      }
      break;
    case 1:
      // etc
  }
}

As can be seen in the second extract, the check is performed on a value that is scaled to be used as a synth paramter. I’ve chosen to control the following potentiometer to parameter mapping:

PotentiometerDescriptionRangeScaling code
1Op 1 Sine Table0-3reading>>8
2Op 1 Frequency0-15reading>>6
3Op 1 Detune0-15reading>>6
4Feedback0-7reading>>7
5Op 2 Sine Table0-3reading>>8
6Op 2 Frequency0-15reading>>6
7Op 2 Detune0-15reading>>6
8Modulation Level0-99reading>>3

I’ve left out the envelope generator options (AD from the UI, but others are available over MIDI) so if these are changed from the keyboard then a further memory dump will be required to resynchronise the Arduino.

Each supported parameter has a get/set function as described previously for the sine table.

The modulation parameter is a little more complex than the others. The official range of values is 0 to 99, but this maps onto a 7-bit MIDI control value 0-127. But it also maps in a slightly odd way. From the PSS-680 user manual MIDI implementation:

TL: TOTAL LEVEL   0000000 - 99 OF PANEL DATA
                  0000001 - 98 OF PANEL DATA
                  1100011 - 00 OF PANEL DATA
                  1111111 - 00 OF PANEL DATA

There are two TL fields – the one for the modulator (M) corresponds to the modulation level; the one for the carrier (C) corresponds to the final output level – I’m only concerned with the modulator level here.

So a MIDI value of 0 maps onto “full modulation” and a MIDI value of >99 maps onto “no modulation”.

There is also an issue with analog accuracy and drifting, so I’ve implemented a smoothing algorithm (more here) to ensure only significant changes cause the value to be updated:

#define AVGEREADINGS 16
int modpotvals[AVGEREADINGS];
int modpotidx;
int modpottotal;

int modpotAverage (int reading) {
  modpottotal = modpottotal - modpotvals[modpotidx];
  modpotvals[modpotidx] = reading;
  modpottotal = modpottotal + modpotvals[modpotidx];
  modpotidx++;
  if (modpotidx >= AVGEREADINGS) modpotidx = 0;
  return (modpottotal / AVGEREADINGS);
}

bool updateSynthParams(int pot, unsigned reading) {
  switch (pot) {
    // other pots
    case 7:
      modreading = modpotAverage(reading)>>3;
      if (updatePotReading(pot, modreading)) {
        setMTL (127-modreading);
        return true;
      }
      break;
  }
}

All the scaling and update checking is performed on the “raw” analog reading, so that a default setting of the potentiometer to 0 doesn’t trigger a number of updates (as it would be interpreted as a value of 99). No further adjusting of the parameter from the 0..127 range is performed as the manual clearly shows what happens to values over 99 (i.e. they are all treated the same – as 0).

Find it on GitHub here.

Closing Thoughts

The video shows the Arduino changing the frequency of both operators, the feedback level, the modulation level and then the sine tables for each operator. I’ve fiddled about with the detune options and whilst I might be able to hear a bit of a difference, I’m not totally convinced. That is one for some further experimentation in the future.

I’ve been really impressed with the capabilities of the PSS-680 and wonder what was in the original vision for the keyboard. I can’t imagine more than a small fraction of owners would have explored the full extent of its MIDI functionality, so was all this additional functionality just for advanced usage?
Or was it thought that owners would really get into the nuts and bolts and use all these features?

Kevin

Leave a comment