OrganProject

Check-in [9970a88933]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Added wavetables and quick presets
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:9970a8893373463171aa97d348fd4db7d308e289
User & Date: 200002852 2009-08-20 03:42:55
Context
2009-08-23
03:03
Added serial communications (over a PS/2 [IBM AT] keyboard cable) between the LED control module and the terminal check-in: ac332e3e60 user: 200002852 tags: trunk
2009-08-20
03:42
Added wavetables and quick presets check-in: 9970a88933 user: 200002852 tags: trunk
2009-08-19
23:44
Completed stop list in the menus check-in: d386cb24e6 user: 200002852 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to stops.txt.

342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
7b 00 0e 00 70 7c 19 22 01 57 6a 1f 3f 24 7d 78
Rankett 8' A
            R 25.4 M00R1269
48 6b 3f 74 5a 11 08 05 05 6d 02 0e 7c 0a 06 7a
Rankett 8' B
              31.1 M00R1346
7c 11 2b 0e 5e 69 1b 1b 6e 41 6a 18 37 22 14 06
Reed Chorus 8' & 4'
            R 30.0 M00R1265
66 75 1b 62 73 60 2c 0b 0b 4c 09 0e 3f 0a 1c 1c
Reed Extender
                   M00R1172
61 7c 1d 79 70 00 09 03 0c 5f 15 71 1c 76 77 7d
Reed Harmonics Bright
              34.6 M00R1267







|







342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
7b 00 0e 00 70 7c 19 22 01 57 6a 1f 3f 24 7d 78
Rankett 8' A
            R 25.4 M00R1269
48 6b 3f 74 5a 11 08 05 05 6d 02 0e 7c 0a 06 7a
Rankett 8' B
              31.1 M00R1346
7c 11 2b 0e 5e 69 1b 1b 6e 41 6a 18 37 22 14 06
Reed Chorus 8'&4'
            R 30.0 M00R1265
66 75 1b 62 73 60 2c 0b 0b 4c 09 0e 3f 0a 1c 1c
Reed Extender
                   M00R1172
61 7c 1d 79 70 00 09 03 0c 5f 15 71 1c 76 77 7d
Reed Harmonics Bright
              34.6 M00R1267

Changes to terminal/makeMenus.tcl.

13
14
15
16
17
18
19








































20
21
22
23
24


25
26
27
28
29
30
31
..
83
84
85
86
87
88
89







90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
...
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
...
602
603
604
605
606
607
608

609
610
611
612
613
614
615
...
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645



























646
647
648
649
650
651
652
653
654
655
656
657
658

659
660
661
662
663
664
665








666
#		         describes all the stops that appear in the menus
#	    menus.c - Contains the C definitions of all the menus.
#
#------------------------------------------------------------------------------
 
#------------------------------------------------------------------------------
#








































# init --
#
#	Initializes global variables
#
# The following variables are used throughout:


#	menuNames - Dictionary whose keys give the names of all menus defined
#		    so far, and whose values are immaterial.
#	programText - List containing the lines of the program that have
#		      been constructed so far
#	stopCNames - Dictionary whose keys are the names of the stops as they
#		     will appear in C source code and whose values are 
#		     immaterial.
................................................................................
# Results:
#	Returns the enumerator.
#
#------------------------------------------------------------------------------

proc makeStop {stopName} {
    variable stopCNames







    regsub -all {(\d)'} $stopName {\1FOOT} cname
    set cname [string map {
	{ 2/3} TWOTHIRDS { 3/5} THREEFIFTHS { 1/3} ONETHIRD
	{ 1/7} ONESEVENTH
    } $cname]
    regsub -all {[^[:alnum:]]} $cname _ cname
    set cname STOP_[string toupper $cname]
    dict set stopCNames $cname {}
    set shorter [string map {
	{ 2/3} \2\4 { 3/5} \3\5 { 1/3} \1\4 { 1/7} \1\7
	Oboe Oboe oe \xef
    } $stopName]
    if {[string length $shorter] > 18} {
	puts "$stopName: name too long?"
    }
................................................................................
    {Bassoon 8' B}
    {Bombarde 8'}
    {Chorus Reed}
    {Clarinet 8'}
    {Clarinet Harmonic}
    {Clarinet Metal MF}
    {Clarinet Metal F}
    {Clarinet Wood}
    {Clarion Harm 4'}
    {Classic Reed No. 1}
    {Cornet 8'}
    {Cornopean 8' A}
    {Cornopean 8' B}
    {Cromorne 8'}
    {Dulzian 8'}
................................................................................
    {Krumet 8'}
    {Krummhorn Harm 8'}
    {Krummhorn No. 1 8'}
    {Krummhorn No. 2 8'}
    {Krummregal 8'}
    {Musette 8'}
    {Oboe Horn 8'}
    {Orch. Oboe 8'}
    {Orch. Schalmei 8'}
    {Orch. Tuba 8'}
    {Petit Rankett 8'}
    {Posaune 8'}
    {Post Horn 8'}
    {Rankett 8' A}
    {Rankett 8' B}
    {Reed Chorus 8'&4'}
    {Reed Extender}
................................................................................
stopMenu percMenu programMenu {*}{
    {Bell 8' 2 2/3' 1'}
    Chimes
    {Crystal Bell}
    {Dolce Bell}
    Multi-Bell
    Octa-Bell

    {Tierce Bell}
    {Tubular Chimes}
}
 

# Write the file header

................................................................................
puts $CFile "/* String literals */"
puts $CFile ""
dict for {val slot} $stringIndex {
    set val [string map {
	{ 2/3} \\2\\4 { 3/5} \\3\\5 { 1/3} \\1\\4 { 1/7} \\1\\7
	Oboe Oboe oe \\xef\"\"
    } $val]
    # TODO - Look up 
    puts $CFile "static const char S$slot\[\] PROGMEM = \"$val\";"
}

# Write the menu declarations

puts $CFile ""
puts $CFile "/* Declarations of menus (for forward references) */"
puts $CFile ""
foreach menu [lsort -dictionary [dict keys $menuNames]] {
    puts $CFile "extern Menu $menu;"
}




























# Write the menus themselves

puts $CFile ""
puts $CFile "/* Menus */"
indent $CFile $programText

close $CFile

# Write the stop list

set f [open stoplist.h w]
puts $f "enum Stop \{"

set i 0
foreach name [lsort -dictionary [dict keys $stopCNames]] {
    puts $f "    $name,"
}
puts $f "\};"
close $f









exit







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





>
>







 







>
>
>
>
>
>
>







|







 







|







 







|

|







 







>







 







<











>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>













>







>
>
>
>
>
>
>
>

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
...
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
...
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
...
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
...
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
...
677
678
679
680
681
682
683

684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
#		         describes all the stops that appear in the menus
#	    menus.c - Contains the C definitions of all the menus.
#
#------------------------------------------------------------------------------
 
#------------------------------------------------------------------------------
#
# loadStops -
#
#	Load the stop data from 'stops.txt'
#
#------------------------------------------------------------------------------

proc loadStops {} {
    variable waveform {}
    set f [open ../stops.txt r]
    set data [read $f]
    close $f
    foreach {name info wave} [split $data \n] {
	regsub {//.*} $name {} name
	set name [string trim $name]
	if {$name eq {}} continue
	foreach map {
	    {{ and } & {No. } # Harmonics Harm Orchestral Orch. Orchestre Orch. 
		Harmonique Harm Seminar * Harmonic Harm Dissonant Diss.}
	    {{ 8'} {} { 4'} {}}
	    {}
	} {
	    set short \
		[string map \
		     [list { 2/3} \2\4 { 3/5} \3\5 { 1/3} \1\4 { 1/7} \1\7]\
		     $name]
	    if {[string length $short] > 18} {
		set name [string map $map $name]
	    }
	}
	if {[string length $short] > 18} {
	    puts "$name too long"
	} else {
	    dict set waveform $name $wave
	}
    }
}
loadStops
 
#------------------------------------------------------------------------------
#
# init --
#
#	Initializes global variables
#
# The following variables are used throughout:
#	didStop - Dictionary whose keys give the names of stops that have been
#		  processed and whose values are immaterial
#	menuNames - Dictionary whose keys give the names of all menus defined
#		    so far, and whose values are immaterial.
#	programText - List containing the lines of the program that have
#		      been constructed so far
#	stopCNames - Dictionary whose keys are the names of the stops as they
#		     will appear in C source code and whose values are 
#		     immaterial.
................................................................................
# Results:
#	Returns the enumerator.
#
#------------------------------------------------------------------------------

proc makeStop {stopName} {
    variable stopCNames
    variable waveform
    variable didStop
    if {![dict exists $waveform $stopName]} {
	puts "$stopName not found?"
    } else {
	dict set didStop $stopName {}
    }
    regsub -all {(\d)'} $stopName {\1FOOT} cname
    set cname [string map {
	{ 2/3} TWOTHIRDS { 3/5} THREEFIFTHS { 1/3} ONETHIRD
	{ 1/7} ONESEVENTH
    } $cname]
    regsub -all {[^[:alnum:]]} $cname _ cname
    set cname STOP_[string toupper $cname]
    dict set stopCNames $cname [dict get $waveform $stopName]
    set shorter [string map {
	{ 2/3} \2\4 { 3/5} \3\5 { 1/3} \1\4 { 1/7} \1\7
	Oboe Oboe oe \xef
    } $stopName]
    if {[string length $shorter] > 18} {
	puts "$stopName: name too long?"
    }
................................................................................
    {Bassoon 8' B}
    {Bombarde 8'}
    {Chorus Reed}
    {Clarinet 8'}
    {Clarinet Harmonic}
    {Clarinet Metal MF}
    {Clarinet Metal F}
    {Clarinet Wood 8'}
    {Clarion Harm 4'}
    {Classic Reed No. 1}
    {Cornet 8'}
    {Cornopean 8' A}
    {Cornopean 8' B}
    {Cromorne 8'}
    {Dulzian 8'}
................................................................................
    {Krumet 8'}
    {Krummhorn Harm 8'}
    {Krummhorn No. 1 8'}
    {Krummhorn No. 2 8'}
    {Krummregal 8'}
    {Musette 8'}
    {Oboe Horn 8'}
    {Orchestral Oboe 8'}
    {Orch. Schalmei 8'}
    {Orchestral Tuba 8'}
    {Petit Rankett 8'}
    {Posaune 8'}
    {Post Horn 8'}
    {Rankett 8' A}
    {Rankett 8' B}
    {Reed Chorus 8'&4'}
    {Reed Extender}
................................................................................
stopMenu percMenu programMenu {*}{
    {Bell 8' 2 2/3' 1'}
    Chimes
    {Crystal Bell}
    {Dolce Bell}
    Multi-Bell
    Octa-Bell
    Quadra-Bell
    {Tierce Bell}
    {Tubular Chimes}
}
 

# Write the file header

................................................................................
puts $CFile "/* String literals */"
puts $CFile ""
dict for {val slot} $stringIndex {
    set val [string map {
	{ 2/3} \\2\\4 { 3/5} \\3\\5 { 1/3} \\1\\4 { 1/7} \\1\\7
	Oboe Oboe oe \\xef\"\"
    } $val]

    puts $CFile "static const char S$slot\[\] PROGMEM = \"$val\";"
}

# Write the menu declarations

puts $CFile ""
puts $CFile "/* Declarations of menus (for forward references) */"
puts $CFile ""
foreach menu [lsort -dictionary [dict keys $menuNames]] {
    puts $CFile "extern Menu $menu;"
}

# Write the wavetables

puts $CFile ""
puts $CFile "/* Wavetables for the stops */"
puts $CFile ""
puts -nonewline $CFile "const byte WaveTables\[]\[16] PROGMEM = \{"
set sep {}
foreach name [lsort -dictionary [dict keys $stopCNames]] {
    puts $CFile $sep
    set sep ,
    puts $CFile "    /* $name */"
    puts -nonewline $CFile "    \{ "
    set sep2 {}
    set i 0
    foreach byte [dict get $stopCNames $name] {
	puts -nonewline $CFile $sep2
	if {[incr i] == 9} {
	    puts -nonewline $CFile "\n      "
	}
	puts -nonewline $CFile 0x$byte
	set sep2 ", "
    }
    puts -nonewline $CFile " \}"
}
puts $CFile {}
puts $CFile \}\;

# Write the menus themselves

puts $CFile ""
puts $CFile "/* Menus */"
indent $CFile $programText

close $CFile

# Write the stop list

set f [open stoplist.h w]
puts $f "enum Stop \{"
puts $f "    STOP_NONE = 0,"
set i 0
foreach name [lsort -dictionary [dict keys $stopCNames]] {
    puts $f "    $name,"
}
puts $f "\};"
close $f

# Check that all the stops are covered.

foreach stop [dict keys $waveform] {
    if {![dict exists $didStop $stop]} {
	puts "$stop is unreachable"
    }
}

exit

Changes to terminal/terminal.pde.

1
2
3
4


5
6
7
8
9
10
11
12
13
14
15
16

17

18
19
20
21
22
23
24
...
685
686
687
688
689
690
691

692
693
694
695
696
697
698
699
700

701
702
703
704
705
706
707
...
708
709
710
711
712
713
714



715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733













734
735
736
737
738
739
740
...
762
763
764
765
766
767
768

769

770
771
772
773
774
775
776
...
858
859
860
861
862
863
864

865
866







867
868
869
870


871
872
873
874
875
876
877
...
884
885
886
887
888
889
890




891









892
893
894
895
896
897
898
899
...
912
913
914
915
916
917
918

































919








920
921
922
923
924
925
926
#include "stoplist.h"

#include <avr/pgmspace.h>
#include <avr/eeprom.h>



extern "C" void __cxa_pure_virtual() {
  while (1) {}
}
 
/*---------------------------------------------------------------------------*
 *                                                                           *
 *			     	EEPROM LAYOUT				     *
 *									     *
 *---------------------------------------------------------------------------*/

enum EEPROM_address {

  EEPROM_DISP_BRIGHTNESS,	/* Last display brightness setting */

};
 
/*---------------------------------------------------------------------------*
 *                                                                           *
 *			     KEYPAD DEFINITIONS				     *
 *                                                                           *
 *---------------------------------------------------------------------------*/
................................................................................
				 * on the keypad */
} Menu;

enum menuFlags {
  MENU_UP	= 0x01,
  MENU_DOWN	= 0x02,
  MENU_MAIN	= 0x04,

};

#define MENU_TIMEOUT_MILLIS 30000 
				/* Menus time out after 30 s of inactivity */

/* RAM for the menu system */

Menu* menuCurrent;		/* Current menu on display */
int menuLastKeyMillis;		/* Time the last keypress happened */


/* Forward function declarations */

Menu* menuSelHandler(byte);	/* Handler for menus that are just
				 * selections that dispatch to other
				 * menus */

................................................................................
Menu* mainMenuHandler(byte);	/* Handler for the main menu */

Menu* brightMenuHandler(byte);	/* Handler for the 'brightness' menu  */\

Menu* stopMenuHandler(byte);	/* Handler for menus that present lists
				 * of 3-5 stops with navigation on 69*# */




/* Bring in the menu data proper */

extern Menu mainMenu;
#include "menus.c"

const char mainMenuLine1[] PROGMEM = "| Organum Antiquum |";
const char mainMenuLine2[] PROGMEM = "+------------------+";
const char mainMenuLine3[] PROGMEM = "";

Menu mainMenu PROGMEM = {
  { mainMenuLine1, mainMenuLine2, mainMenuLine3 },
  mainMenuHandler, MENU_MAIN,
  {
    NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL,
    &programMenu
  }
};














 
/*
 *-----------------------------------------------------------------------------
 *
 * menuShow --
 * 
 *	Paints a menu on the screen and sets it as the current menu.
................................................................................
    dispWriteStringPGM((const char*)pgm_read_word(&(menu->screenContent[i])));
  }
  i = pgm_read_byte(&(menu->flags));
  dispMoveTo(3,0); 
  if (i & MENU_MAIN) {
    dispWriteStringPGM(PSTR("*:Program     #:Card"));
  } else {

    dispWriteStringPGM(PSTR("*:Back"));

    if (i & MENU_UP) {
      dispMoveTo(3,7); dispWriteStringPGM(PSTR("6:^"));
    }
    if (i & MENU_DOWN) {
      dispMoveTo(3,11); dispWriteStringPGM(PSTR("9:\6"));
    }
    if (i & (MENU_UP | MENU_DOWN)) {
................................................................................
 *	Handle keypresses on a menu to select stops
 *
 *-----------------------------------------------------------------------------
 */

Menu*
stopMenuHandler(byte key) {

  if (key >= 1 && key <= 5) {
    /* TODO: Select a stop and ask what to do with it. */







    return &mainMenu;
  } else {
    return menuSelHandler(key);
  }


}
 
/*
 *-----------------------------------------------------------------------------
 *
 * mainMenuHandler --
 *
................................................................................
 *
 *-----------------------------------------------------------------------------
 */
Menu*
mainMenuHandler(byte key)
{
  /* TODO - come out of standby */




  /* TODO - quick programming of stops */









  if (key == KP_ASTERISK) {
    return &programMenu;
  }
  return &mainMenu;
}
 
/*
 *-----------------------------------------------------------------------------
................................................................................
{
  if (key <= 9) {
    dispSetBrightness(key);
  }
  return &mainMenu;
}
 

































void 








setup() {

  kpInit();			/* Initialize the keypad */

  dispInit();			/* Initialize the display */

  menuLastKeyMillis = millis();




>
>












>
|
>







 







>









>







 







>
>
>







|











>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
|
>







 







>

<
>
>
>
>
>
>
>
|
<
<
|
>
>







 







>
>
>
>
|
>
>
>
>
>
>
>
>
>
|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
...
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
...
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
...
882
883
884
885
886
887
888
889
890

891
892
893
894
895
896
897
898


899
900
901
902
903
904
905
906
907
908
...
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
...
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
#include "stoplist.h"

#include <avr/pgmspace.h>
#include <avr/eeprom.h>

void sendToOrgan(void);

extern "C" void __cxa_pure_virtual() {
  while (1) {}
}
 
/*---------------------------------------------------------------------------*
 *                                                                           *
 *			     	EEPROM LAYOUT				     *
 *									     *
 *---------------------------------------------------------------------------*/

enum EEPROM_address {
  EEPROM_QUICK_STOP = 0,	/* Wavetables for 10 quick stop settings */
  EEPROM_DISP_BRIGHTNESS = 160,	/* Last display brightness setting */
  
};
 
/*---------------------------------------------------------------------------*
 *                                                                           *
 *			     KEYPAD DEFINITIONS				     *
 *                                                                           *
 *---------------------------------------------------------------------------*/
................................................................................
				 * on the keypad */
} Menu;

enum menuFlags {
  MENU_UP	= 0x01,
  MENU_DOWN	= 0x02,
  MENU_MAIN	= 0x04,
  MENU_NOBACK   = 0x08,
};

#define MENU_TIMEOUT_MILLIS 30000 
				/* Menus time out after 30 s of inactivity */

/* RAM for the menu system */

Menu* menuCurrent;		/* Current menu on display */
int menuLastKeyMillis;		/* Time the last keypress happened */
byte selectedStop[16];		/* Wavetable of the selected stop */

/* Forward function declarations */

Menu* menuSelHandler(byte);	/* Handler for menus that are just
				 * selections that dispatch to other
				 * menus */

................................................................................
Menu* mainMenuHandler(byte);	/* Handler for the main menu */

Menu* brightMenuHandler(byte);	/* Handler for the 'brightness' menu  */\

Menu* stopMenuHandler(byte);	/* Handler for menus that present lists
				 * of 3-5 stops with navigation on 69*# */

Menu* gotStopMenuHandler(byte);	/* Handler for menu that is displayed
				 * after a stop is selected. */

/* Bring in the menu data proper */

extern Menu mainMenu;
#include "menus.c"

const char mainMenuLine1[] PROGMEM = "| Organum Antiquum |";
const char mainMenuLine2[] PROGMEM = "+------------------+";
const char mainMenuLine3[] PROGMEM = "0-9: Quick Stop";

Menu mainMenu PROGMEM = {
  { mainMenuLine1, mainMenuLine2, mainMenuLine3 },
  mainMenuHandler, MENU_MAIN,
  {
    NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL,
    &programMenu
  }
};

const char gotStopMenuLine1[] PROGMEM = " \xff Stop selected. \xff ";
const char gotStopMenuLine2[] PROGMEM = "0-9:Save Quick Stop";
const char gotStopMenuLine3[] PROGMEM = "  *:Send To Organ";

Menu gotStopMenu PROGMEM = {
  { gotStopMenuLine1, gotStopMenuLine2, gotStopMenuLine3 },
  gotStopMenuHandler, MENU_NOBACK, 
  {
    NULL, NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, NULL, NULL,
    NULL
  }
};
 
/*
 *-----------------------------------------------------------------------------
 *
 * menuShow --
 * 
 *	Paints a menu on the screen and sets it as the current menu.
................................................................................
    dispWriteStringPGM((const char*)pgm_read_word(&(menu->screenContent[i])));
  }
  i = pgm_read_byte(&(menu->flags));
  dispMoveTo(3,0); 
  if (i & MENU_MAIN) {
    dispWriteStringPGM(PSTR("*:Program     #:Card"));
  } else {
    if (!(i & MENU_NOBACK)) {
      dispWriteStringPGM(PSTR("*:Back"));
    }
    if (i & MENU_UP) {
      dispMoveTo(3,7); dispWriteStringPGM(PSTR("6:^"));
    }
    if (i & MENU_DOWN) {
      dispMoveTo(3,11); dispWriteStringPGM(PSTR("9:\6"));
    }
    if (i & (MENU_UP | MENU_DOWN)) {
................................................................................
 *	Handle keypresses on a menu to select stops
 *
 *-----------------------------------------------------------------------------
 */

Menu*
stopMenuHandler(byte key) {
  unsigned short stopNum;
  if (key >= 1 && key <= 5) {

    stopNum = pgm_read_word(menuCurrent->clientData + key);
    if (stopNum != 0) {
      const byte* p = WaveTables[stopNum-1];
      byte i;
      for (i = 0; i < 16; ++i) {
	selectedStop[i] = pgm_read_word(p+i);
      }
      return &gotStopMenu;


    }
  }
  return menuSelHandler(key);
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * mainMenuHandler --
 *
................................................................................
 *
 *-----------------------------------------------------------------------------
 */
Menu*
mainMenuHandler(byte key)
{
  /* TODO - come out of standby */

  if (key <= 9) {

    /* 
     * Quick programming of stops - pull a preset from EEPROM and send
     * it to the organ.
     */
    byte i;
    unsigned short addr = 16 * key;
    for (i = 0; i < 16; ++i) {
      selectedStop[i] = eeprom_read_byte((byte*)(EEPROM_QUICK_STOP + addr));
      ++addr;
    }
    sendToOrgan();
  } else if (key == KP_ASTERISK) {
    return &programMenu;
  }
  return &mainMenu;
}
 
/*
 *-----------------------------------------------------------------------------
................................................................................
{
  if (key <= 9) {
    dispSetBrightness(key);
  }
  return &mainMenu;
}
 
/*
 *-----------------------------------------------------------------------------
 *
 * gotStopMenuHandler --
 *
 *	Handle keypresses once a stop is selected
 *
 * Digits 0-9 save the stop for quick access.  * sends it to the organ.
 *
 *-----------------------------------------------------------------------------
 */

Menu*
gotStopMenuHandler(byte key)
{
  if (key <= 9) {
    /* 
     * Quick programming of stops - put a preset into EEPROM.
     */
    byte i;
    unsigned short addr = 16 * key;
    for (i = 0; i < 16; ++i) {
      eeprom_write_byte((byte*)(EEPROM_QUICK_STOP + addr), selectedStop[i]);
      ++addr;
    }
  } else if (key == KP_ASTERISK) {
    sendToOrgan();
  }
  return &mainMenu;
}
 
/* TODO - UNSTUB THIS */

void
sendToOrgan(void) {
  dispClear();
  dispWriteStringPGM(PSTR("SEND"));
  delay(2000);
  menuShow(menuCurrent);
}
 
void
setup() {

  kpInit();			/* Initialize the keypad */

  dispInit();			/* Initialize the display */

  menuLastKeyMillis = millis();