Skip to content

PSG Envelopes

Robert Hargreaves edited this page May 10, 2020 · 5 revisions

PSG envelopes are defined based on a format called the Echo Envelope Format (or EEF) introduced with the Echo sound engine. This project's implementation is mostly faithful to the original spec, with some differences.

An envelope is declared as an array of bytes, where each byte represents a tick. For example:

u8 envelope[] = { 0x00, 0x01, 0x01, 0x01, 0x01, 
    EEF_LOOP_START, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, EEF_LOOP_END,
    0x01, 0x02, 0x03, 0x04, 0x05,
    0x06, 0x07, 0x08, 0x09, 0x0A,
    0x0B, 0x0C, 0x0D, 0x0E, 0x0F, EEF_END }

The tick's frequency is either 60 Hz for NTSC systems or 50 Hz for PAL. The byte defines the appropriate pitch shift & attenuation to be applied.

Envelopes must be terminated with EEF_END (0xFF).

Built-in envelopes are applied by choosing the appropriate MIDI program, as defined in the code, or by loading a user-defined envelope via SysEx.

Attenuation

The lower nibble of the byte defines the attenuation (16 possible values):

0x?0 = Minimum (loudest)
...
0x?F = Maximum (silence)

Applying attenuation within a loop can be used to achieve a tremolo effect.

Pitch Shift

The upper nibble can be used to define a pitch shift:

      0x0? = No pitch shift
-----------------------------------
0x1? = +0.05 st     0x8? = -0.05 st
0x2? = +0.1 st      0x9? = -0.1 st
0x3? = +0.2 st      0xA? = -0.2 st
0x4? = +0.5 st      0xB? = -0.5 st
0x5? = +1 st        0xC? = -1 st
0x6? = +2 st        0xD? = -2 st
0x7? = +5 st        0xE? = -5 st

Applying pitch shift within a loop can be used to achieve a vibrato effect. Note that these values are different to the original EEF specification, so existing instruments may need to be adjusted to suit.

Looping

You can loop the envelope by specifying EEF_LOOP_START (0xFE) and marking the end either with EEF_END or EEF_LOOP_END (0xFD):

  • EEF_END marks the end of the envelope, as well as the loop. You cannot define anything after that point. When the note is released, the envelope will end.
  • EEF_LOOP_END marks the end of the loop but will allow you to define steps that are followed when the note is released. This is useful if you wish to gradually fade out the note after the main loop section.

Note Release

If a note up event is received, the envelope will stop immediately unless it is in the middle of a loop, in which case it will complete the current loop iteration and then continue with any defined steps after the loop.

How does this map to ADSR?

Roughly:

  • Attack & Decay = Steps before loop
  • Sustain = Loop
  • Release = Steps after loop

Differences to the original Echo EEF specification

  • EEF_LOOP_END is unsupported in the original specification.
  • The pitch shift values are different in this project, allowing for fractions of semitones.

Loading User Defined Envelopes

You can load a custom EEF envelope into the interface by sending the EEF encoded after a specific SysEx sequence:

00 22 77 06 ...

Then encode the EEF by splitting each byte into two separate nibbles and sending each nibble along the wire, big-endian. You do not need to terminate the EEF in the encoded SysEx message. For example:

EEF: FE 00 12 FF --> SysEx: 00 22 77 06 0F 0E 00 00 01 02

The envelope will then replace the built-in envelopes until the console is reset.