/* Arexx macro to insert the preset number for a given GM instrument */
/* by Keith Barkley   10/93 */

/* Set up number/name array.  Names from GM document off of the internet. */
/* Well, some names are from my Dr Synth... 8^)                         */
/* Change it if you want to. */

namef = 0  /* Because I don't know how to pass arrays... */
groupf = 1

group.      = "NULL"
name.       = "NULL"

group.1                = "PIANO"   ;
name.1           = "GRAND PIANO"   ;  name.2           = "BRIGHT PIANO"  
name.3  = "ELECTRIC GRAND PIANO"   ;  name.4       = "HONKY-TONK PIANO" 
name.5      = "ELECTRIC PIANO 1"   ;  name.6       = "ELECTRIC PIANO 2"  
name.7           = "HARPSICHORD"   ;  name.8             = "CLAVICHORD"

group.2  = "CHROMATIC PERCUSSION"  ; 
name.9               = "CELESTA"   ;  name.10          = "GLOCKENSPIEL"  
name.11            = "MUSIC BOX"   ;  name.12            = "VIBRAPHONE" 
name.13              = "MARIMBA"   ;  name.14             = "XYLOPHONE" 
name.15        = "TUBULAR BELLS"   ;  name.16              = "DULCIMER"

group.3                = "ORGAN"   ;  
name.17        = "DRAWBAR ORGAN"   ;  name.18      = "PERCUSSIVE ORGAN" 
name.19           = "ROCK ORGAN"   ;  name.20          = "CHURCH ORGAN" 
name.21           = "REED ORGAN"   ;  name.22             = "ACCORDION" 
name.23            = "HARMONICA"   ;  name.24             = "BANDONEON"

group.4               = "GUITAR"   ;
name.25     = "NYLON STR GUITAR"   ;  name.26     = "STEEL STR GUITAR" 
name.27          = "JAZZ GUITAR"   ;  name.28         = "CLEAN GUITAR"  
name.29         = "MUTED GUITAR"   ;  name.30    = "OVERDRIVEN GUITAR" 
name.31    = "DISTORTION GUITAR"   ;  name.32     = "GUITAR HARMONICS" 

group.5                 = "BASS"   ; 
name.33        = "ACOUSTIC BASS"   ;  name.34         = "FINGERED BASS" 
name.35          = "PICKED BASS"   ;  name.36         = "FRETLESS BASS" 
name.37          = "SLAP BASS 1"   ;  name.38           = "SLAP BASS 2"  
name.39         = "SYNTH BASS 1"   ;  name.40          = "SYNTH BASS 2"

group.6              = "STRINGS" 
name.41               = "VIOLIN"   ;  name.42                 = "VIOLA"  
name.43                = "CELLO"   ;  name.44            = "CONTRABASS" 
name.45      = "TREMOLO STRINGS"   ;  name.46     = "PIZZICATO STRINGS" 
name.47                 = "HARP"   ;  name.48               = "TIMPANI"

group.7            = "ENSEMBLE"
name.49              = "STRINGS"   ;  name.50          = "SLOW STRINGS" 
name.51      = "SYNTH STRINGS 1"   ;  name.52       = "SYNTH STRINGS 2" 
name.53           = "CHOIR AAHS"   ;  name.54            = "VOICE OOHS"
name.55          = "SYNTH VOICE"   ;  name.56         = "ORCHESTRA HIT" 

group.8               = "BRASS"
name.57              = "TRUMPET"   ;  name.58              = "TROMBONE"  
name.59                 = "TUBA"   ;  name.60         = "MUTED TRUMPET" 
name.61          = "FRENCH HORN"   ;  name.62               = "BRASS 1"
name.63        = "SYNTH BRASS 1"   ;  name.64         = "SYNTH BRASS 2" 

group.9                = "REED"
name.65          = "SOPRANO SAX"   ;  name.66              = "ALTO SAX" 
name.67            = "TENOR SAX"   ;  name.68          = "BARITONE SAX"  
name.69                 = "OBOE"   ;  name.70          = "ENGLISH HORN"
name.71              = "BASSOON"   ;  name.72              = "CLARINET" 

group.10              = "PIPE" 
name.73              = "PICCOLO"   ;  name.74                 = "FLUTE" 
name.75             = "RECORDER"   ;  name.76             = "PAN FLUTE" 
name.77         = "BLOWN BOTTLE"   ;  name.78            = "SHAKUHACHI"
name.79              = "WHISTLE"   ;  name.80               = "OCARINA" 

group.11       =  "SYNTH LEAD"
name.81          = "SQUARE WAVE"   ;  name.82         = "SAWTOOTH WAVE" 
name.83       = "SYNTH CALLIOPE"   ;  name.84               = "CHIFFER"
name.85              = "CHARANG"   ;  name.86              = "SOLO VOX" 
name.87      =  "FIFTH SAW WAVE"   ;  name.88         = "BASS AND LEAD" 

group.12       = "SYNTH PAD" 
name.89              = "FANTASIA"   ;  name.90                 = "WARM" 
name.91             = "POLYSYNTH"   ;  name.92          = "SPACE VOICE" 
name.93           = "BOWED GLASS"   ;  name.94                = "METAL" 
name.95                  = "HALO"   ;  name.96                = "SWEEP" 

group.13      = "SYNTH EFFECTS"
name.97              = "ICE RAIN"   ;  name.98           = "SOUNDTRACK"  
name.99               = "CRYSTAL"   ;  name.100          = "ATMOSPHERE"
name.101           = "BRIGHTNESS"   ;  name.102              = "GOBLIN"  
name.103           = "ECHO DROPS"   ;  name.104          = "STAR THEME" 

group.14            = "ETHNIC"
name.105                = "SITAR"   ;  name.106               = "BANJO" 
name.107             = "SHAMISEN"   ;  name.108                = "KOTO"
name.109              = "KALIMBA"   ;  name.110             = "BAGPIPE" 
name.111               = "FIDDLE"   ;  name.112              = "SHANAI"

group.15       = "PERCUSSIVE" 
name.113          = "TINKLE BELL"   ;  name.114              = "AGOGO"
name.115          = "STEEL DRUMS"   ;  name.116          = "WOODBLOCK" 
name.117                = "TAIKO"   ;  name.118        = "MELODIC TOM"  
name.119           = "SYNTH DRUM"   ;  name.120     = "REVERSE CYMBAL" 

group.16    = "SOUND EFFECTS"
name.121    = "GUITAR FRET NOISE"   ;  name.122       = "BREATH NOISE" 
name.123             = "SEASHORE"   ;  name.124         = "BIRD TWEET" 
name.125            = "TELEPHONE"   ;  name.126         = "HELICOPTER" 
name.127             = "APPLAUSE"   ;  name.128            = "GUNSHOT"  




T= ' TITLE "GM Instrument Request"'


/* Get name or help request */
OPTIONS RESULTS
P = ' PROMPT "Type in the name of the instrument or click HELP."'
D = ' DEFAULT "' || name.1 || '"'
B = ' BUTTONS "_OK|_Help"'

RequestString T || P || D || B 

IF ( RC = 5 ) THEN CALL GET_HELP 

/* user thought they knew the name of the drum */

searchname = UPPER(COMPRESS(RESULT))
patch = 0
DO i = 1 TO 128
	IF (searchname = COMPRESS(name.i) ) THEN DO
		patch = i
		LEAVE i
	END  /* end if */
END
IF (patch  ~= 0) THEN CALL SAY_IT patch

OPTIONS RESULTS
P = ' PROMPT "Could not find ' || searchname || '!"'
B = ' BUTTONS "_Quit|_Help" '

RequestResponse T || P || B 
    
IF (RESULT = 1) THEN CALL GET_HELP
EXIT 0

/**********************************************************/
/* This functions allows the user to select a list or a search */

GET_HELP:
/* Ask for list or search */
OPTIONS RESULTS
P = ' PROMPT "Would you like a List, a Name Search or a Group Search?"'
B = ' BUTTONS "_List|_Name|_Group"'

RequestResponse  T || P || B

res = RESULT

SELECT ;
    WHEN (res = 0) THEN CALL GO_LIST namef, 1, 128
    WHEN (res = 1) THEN CALL GO_SEARCH 
    WHEN (res = 2) THEN CALL GROUP_SEARCH 
END    

CALL SAY_IT RESULT

EXIT 0

/************************************************************/
/*  This function is used to list a set of instruments or groups       */
/*  from 1 to 128 and allows the user to just click the mouse to      */
/*  select the desired instrument.                                  */

GO_LIST:
ARG var, low, high
/* list some number of items in patch order.  provide a number to make */
/* it easy to select..*/

maxlen = 79 /* Length of line available in requester */
n = low - 1   /* the number of the note we want */
i = 0  /* the index */
string = ""
lpatch = 0
request = 0  /* Do we need a request ? */

DO UNTIL (n=high)

    DO UNTIL (var.n ~= "NULL" ) /* In case there are gaps in the list */
        n = n + 1  /* Always done at least once */
    END 
    
    i = i + 1

    /* Build String of form " 1-name1; 2-name2" */
    IF (var = namef) THEN build = ";" || i || "-" || name.n
                     ELSE build = ";" || i || "-" || group.n

    numlist.i = n
    
    IF (LENGTH(string)+LENGTH(build)) > maxlen THEN DO
        request = 1
        n = n-1  /* roll back n */
        i = i - 1 /* i = last index */
    END
    ELSE string = string || build
    
    IF (n = high ) THEN request = 1
    
    IF (request = 1) THEN DO
        string = DELSTR(string, 1, 1)  /* Remove the first semicolon */
        
        OPTIONS RESULTS
        
        ttl = ' TITLE "Click # of desired item."'
        string = ' PROMPT "' || string || '"'
        b = ""
        
        DO bi = 1 TO i  /* build list of button numbers */
            b = b || bi || '|'
        END
        
        b = ' BUTTONS "' || b || '_None"'
        
        RequestResponse ttl || string || b
        
        r = RESULT + 1   /* because it returns the buttons starting at '0'*/
        IF ( r = i+1) THEN DO
            /* set up for next loop */
            string = ""
            i = 0
            request = 0
            /* Note :: Do nothing with n .. we didn't use it yet...*/
            
            ITERATE
        END /* End of ( r = i+1)  IF */
        
        /* Found it ! */
        lpatch = numlist.r
        LEAVE
        
    END /* end of request if */
    
END /* Until n = high do */

RETURN lpatch    /* none found !*/

/*****************************************************/
/*  This function allows the abuser to enter either a letter or      */
/*  a word to search for.  A letter returns all the insruments that  */
/*  start with that letter.  A word matches all instances of that    */
/*  sequence of characters.                                          */

GO_SEARCH:
/* Get search string */
/* If single character then get all names that start with letter. */
/* If multiple characters use index function to find all occurances */

OPTIONS RESULTS

P = ' PROMPT "Enter a character or a word" '
D = ' DEFAULT "" '
B = ' BUTTONS "_OK" '

RequestString T || P || D || B
              
searchstr = UPPER(COMPRESS(RESULT))
len = LENGTH(searchstr)

DO i = 1 TO 128
	ind = INDEX(COMPRESS(name.i) , searchstr)
	IF (ind = 0) THEN ITERATE i              /* str not found */
	IF (len = 1) & (ind > 1 ) THEN ITERATE i /* single letter not 1st */
 	/* String Matches ! */
    OPTIONS RESULTS
    
    P = ' PROMPT "Is ' || name.i || ' correct?"'
    B = ' BUTTONS "_OK|_Next|_Quit" '

	RequestResponse T || P || B
    IF (RESULT = 0) THEN RETURN    i
    IF (RESULT = 2) THEN RETURN    0
END

EXIT 0  /* End of function */


/*  This allows you to list the groups, select it and then list  */
/*  the instruments within that group.                           */

GROUP_SEARCH:

/* First get the group number... */
CALL GO_LIST groupf,1,16
CALL GO_LIST namef, (8 * RESULT - 7), (8*RESULT)

CALL SAY_IT  RESULT

EXIT 0

/*  This is where all the functions come in order to insert the  */
/*  GM instrument preset note number.                            */

SAY_IT:
ARG spatchnum
 
IF ((spatchnum = 0) | (spatchnum > 128) ) THEN EXIT 0
p = 'PROMPT "The preset for '||name.spatchnum||' is '||spatchnum
RequestNotify T || p

EXIT 0
