Software
The program for the microcontroller does all the hard work, and it will be available for free download. It does work, I just need to torture test it. Not any time soon.
Some Source Code
Nerds only: This is what the program looks like, without the variable/constant declarations and the low level I/O subroutines.
This has a diagnostic buzzer, which the downloadable version won't have.


'PicBasic Pro, 16F877 40-pin
'Maps switches to predefined led/relays

'We need 12 Pins for Stomp switches
'3 Pins for other switches (program, bank up, bank down)
'12 pins for relay/led
'Each footswitch is mapped to a "Patch" of relay on/off data
'There are 2 banks of patches, a "Bank" switch toggles between them
'A "Memory" button switches programming mode on and off
'A "Momentary" button switches momentary mode on and off
'In Momentary mode, if you hold down a foot switch for more than a second
'it changes patch instantly, but reverts to the previous patch when
'you release the footswitch.

'--------------------------------------begin main program--------------------------------------

'Convention: subroutines can only go 4 deep, the complier doesn't check.
'so subroutines which call other subroutines have a postfix number
' = number of nesting levels.
'sub means it doesn't GOSUB anything
'sub2 GOSUBs sub, sub3 GOSUBs sub2, sub4 GOSUBS sub3
'GOSUB sub, call stack = 1.
'GOSUB sub2, call stack = 2.
'GOSUB sub3, call stack = 3.
'GOSUB sub4, call stack = 4.
'GOSUB sub5 wraps the call stack around itself. This is very bad

GOSUB init3

WHILE TRUE
   GOSUB process_memory3   'programming mode
   IF memory_held_mh = TRUE THEN
      'memory button still on
      GOSUB program_selected_button3   'Deep nesting, so move it up
   ENDIF  
   GOSUB process_buttons3   'patch selection
   GOSUB process_momentary2   'special mode switch  
   GOSUB process_bank2   'toggle bank of patches
WEND

'--------------------------------------end main program--------------------------------------
process_memory3:   'programming mode
   GOSUB memory_held   'a latching switch, no debouncing
   IF memory_held_mh = TRUE THEN
      buzz_pause = 1
      GOSUB buzz
      'memory button on
      GOSUB wait_for_relay_or_memory_off2   'select button to program
      IF memory_held_mh = TRUE THEN
         'memory button still on
         READ low_addr_bh, low_data_sl
         READ high_addr_bh, high_data_sl        
         GOSUB switch_leds2   'use existing program setting
         'GOSUB program_selected_button3   'Deep nesting, so move it up
      ENDIF
   ENDIF
RETURN

process_buttons3:   'patch selection, non-latching toggle
   GOSUB button_held
   IF button_held_bh <> NOPRESS  THEN
      READ low_addr_bh, low_data_sl
      READ high_addr_bh, high_data_sl
      GOSUB switch_leds2
      PAUSE 90
   ENDIF
RETURN 
  
process_momentary2:  
   GOSUB momentary_held
   'toggle active bank
   IF momentary_held_mh THEN 'a latching switch
      momentary_flag = MOMENTARY_OFF
   ELSE
      momentary_flag = MOMENTARY_ON
   ENDIF
RETURN    


process_bank2:
   GOSUB bank_held
   'toggle active bank
   IF bank_held_bh THEN 'a latching switch 
      'read new bank data
      IF active_bank = BANK_0 THEN
         active_bank = BANK_1
      ELSE
         active_bank = BANK_0
      ENDIF
   'switch to new bank immediately
   'may not be desirable
   'plus, what if no footswitch has been pressed?
   'if you want to go from bk0:patch2 to bk1:patch3
   'you have to go via bk1:patch2
      buzz_pause = 2
      GOSUB buzz  
      PAUSE 50      
   ENDIF     
RETURN


program_selected_button3:
' Input: button_held_bh is the button to program
' We change the button_array, and the EEPROM data.
' There is a high byte and a low byte

   'get existing data
   READ low_addr_bh, low_data_psb 'we edit this, then WRITE it
   READ high_addr_bh, high_data_psb 'we edit this, then WRITE it
   'remember the address of the button to program
   low_addr_psb = low_addr_bh
   high_addr_psb = high_addr_bh   
   GOSUB wait_for_relay_or_memory_off2
buzz_pause = 1  
GOSUB buzz
pause 500
GOSUB buzz    
   'wait for button press and toggle corresponding bit
   'turning off the memory button exits loop  
   WHILE memory_held_mh
      button_byte = button_held_bh
      'Make a mask with one bit set and shift the set bit left
      'to correspond with the footswitch position.
      'Then use XOR to toggle the bit
      mask_psb = %00000001
      'We have to change either the high byte or the low byte
      'We toggle the bit which corresponds to the button pressed
      IF button_byte > 7 THEN   ' high byte
         button_byte = button_byte - 8' button 8 is bit 0 on the high byte
         IF button_byte <> 0 THEN 'first button mean zero shift left, so do nothing
            mask_psb  =  mask_psb << button_byte
         ENDIF     
         high_data_psb = high_data_psb ^ mask_psb  'XOR toggle button_array bit if button hit
      ELSE   'low byte
         IF button_byte <> 0 THEN
            mask_psb  =  mask_psb << button_byte
         ENDIF
         low_data_psb = low_data_psb ^ mask_psb  'XOR toggle button_array bit if button hit
      ENDIF

      high_data_sl = high_data_psb
      low_data_sl = low_data_psb
      GOSUB switch_leds2   'use existing program setting
     
      PAUSE 30'debounce
      GOSUB wait_for_relay_or_memory_off2
   WEND
   'You can only WRITE a limited number of times,
   'so do it when editing is finished
   WRITE low_addr_psb, low_data_psb
   WRITE high_addr_psb, high_data_psb           
   buzz_pause = 3  
   GOSUB buzz  
RETURN

  

init3:
'-------Hardware essentials-------
   DEFINE OSC 4'4MHz
'PIC16F87x series devices will come up in analog mode.
'You must set them to digital if that is how you intend to use them:
   ADCON0 = ADCON_DIGITAL   'A register 
   ADCON1 = ADCON_DIGITAL   'seems to affect the D register 
  
   'Just leave unused pins as low outputs
   TRISA = %00000000   'output for 8 relays
   TRISB = %11111111   'input for 8 footswitches
   TRISC = %11110000   '4 input for footswitches, 4 relays
   TRISD = %11110000   '4 inputs for special switches
   TRISE = %00000000   'relays
  

   INTCON = DISABLE_INTERRUPTS

'-------Default Programming-------  
   'Set defaults once only.   
   READ NUM_RELAYS_TIMES_4, loop_byte 
   IF loop_byte <> PROGRAMMED THEN
      'first time we apply power
      'It doesn't matter if this doesn't alway work
      'Set default switch info for the user to change
      'We start with button n as a on switch for relay n
      'Button 2 has high byte %000000000, low byte %000000100
      'Button 9 has high byte %000000010, low byte %000000000
        
      'low bytes, both banks
      mask_psb = %00000001 
      FOR loop_byte = 0 TO 7
         WRITE loop_byte, mask_psb   'bank0
         WRITE loop_byte + NUM_RELAYS_TIMES_2, mask_psb   'bank1
         mask_psb = mask_psb << 1
         WRITE loop_byte + NUM_RELAYS, %000000000   'bank0
         WRITE loop_byte + NUM_RELAYS_TIMES_3, %000000000   'bank1
      NEXT loop_byte
     
      'high bytes, both banks     
      mask_psb = %00000001 
      FOR loop_byte = 8 TO 11
         WRITE loop_byte, mask_psb   'bank0
         WRITE loop_byte + NUM_RELAYS_TIMES_2, mask_psb   'bank1
         mask_psb = mask_psb << 1
         WRITE loop_byte + NUM_RELAYS, %000000000   'bank0
         WRITE loop_byte + NUM_RELAYS_TIMES_3, %000000000   'bank1        
      NEXT loop_byte
      WRITE NUM_RELAYS_TIMES_4, PROGRAMMED   'never do this again
   ENDIF
   'Read user programmed patches

'-------set toggle switch initial states-------
  
   active_bank = BANK_0
  
'-------hardware test-------

   GOSUB all_on2
   PAUSE 500
   GOSUB all_off2
   PAUSE 500

   buzz_pause = 3  
   GOSUB buzz

RETURN





switch_leds2:
' switch to a preprogrammed led/relay selection
' Input: low_data_sl, high_data_sl
   buzz_pause = 6
   GOSUB buzz

   mask_sl = %00000001   'start with rightmost bit
   FOR relay_roo = 0 TO 7   '8 bits to consider,
      led_sl = low_data_sl & mask_sl   'look at one bit
      IF led_sl = 0 THEN
         on_off_roo = GET_IT_OFF  
      ELSE
         on_off_roo = GET_IT_ON   'bit set = relay on
      ENDIF
      GOSUB relay_on_off
      mask_sl = mask_sl << 1   'next bit to the left
   NEXT relay_roo

   mask_sl = %00000001   'start with rightmost bit
   FOR relay_roo = 8 TO 11   'only 4 bits used on the high bit
      led_sl = high_data_sl & mask_sl   'look at one bit
      IF led_sl = 0 THEN
         on_off_roo = GET_IT_OFF
      ELSE
         on_off_roo = GET_IT_ON
      ENDIF
      GOSUB relay_on_off     
      mask_sl = mask_sl << 1   'next bit to the left
   NEXT relay_roo  
RETURN


all_on2:
   FOR relay_roo = FIRST_BUTTON TO LAST_BUTTON
      on_off_roo = GET_IT_ON
      GOSUB relay_on_off
   NEXT relay_roo
RETURN

all_off2:
   FOR relay_roo = FIRST_BUTTON TO LAST_BUTTON
      on_off_roo = GET_IT_OFF
      GOSUB relay_on_off
   NEXT relay_roo
RETURN


wait_for_relay_or_memory_off2:
'Wait until a relay_button is pressed, or the memory switch is released
'Output: button_held_bh and memory_held_mh
   memory_held_mh = TRUE
   button_held_bh = NOPRESS
   WHILE (memory_held_mh = TRUE) AND (button_held_bh = NOPRESS)
      GOSUB button_held
      GOSUB memory_held
   WEND
   'either memory_held_mh = FALSE or a button pressed
RETURN