'------------------------------------------------------------------------------------------------------------
' SOUNDRA STEREO :: GCONTROLS.bas - Graphical Control Functions
'------------------------------------------------------------------------------------------------------------
#MACRO PATCH_BG()
     LINE DRAWING_DEST, (GDATA.X,GDATA.Y)-(GDATA.X+GDATA.W-1,GDATA.Y+GDATA.H-1), BACKGROUND, BF
     IF (Controls[ID]->SHADED = TRUE) ANDALSO (SETTINGS.USE_SHADER = TRUE) THEN
          ACETATE_TRANSFER(Controls[ID]->IMAGE[Controls[ID]->NB_IMAGES-1],GDATA.X,GDATA.Y)
     END IF
#ENDMACRO
#MACRO STYLE_FLAT_FRAME(OFF_COLOR)
     FRAME_COLOR = OFF_COLOR
     FRAME_STYLE = FR_SOLID
     IF GDATA.state.HOVER  THEN FRAME_COLOR = SWATCH0.FRM_ACTIVE
     IF GDATA.state.ACTIVE THEN FRAME_COLOR = SWATCH0.FRM_ACTIVE
#ENDMACRO

#MACRO STYLE_BUTTON()
     FRAME_COLOR = SWATCH0.BUTTON_FRM_OFF
     IF GDATA.state.HOVER    THEN FRAME_COLOR = SWATCH0.FRM_ACTIVE
     IF GDATA.state.ACTIVE   THEN
          FRAME_STYLE = FR_LIGHT1
          BACKGROUND  = SWATCH0.BUTTON_BG_ACTIVE
          FOREGROUND  = 0
     ELSE
          FRAME_STYLE = FR_LIGHT0
          IF GDATA.state.POWER THEN
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          ELSE
               BACKGROUND = IIF(GDATA.CLR <> 0,GDATA.CLR,SWATCH0.BUTTON_BG)
               FOREGROUND = SWATCH0.BUTTON_FG
          END IF
     END IF
#ENDMACRO
#MACRO STYLE_BUTTON_TAB()
     FRAME_COLOR = SWATCH0.BUTTON_FRM_OFF
     IF GDATA.state.HOVER THEN FRAME_COLOR = SWATCH0.FRM_ACTIVE
     IF GDATA.state.POWER THEN
          FRAME_STYLE = FR_LIGHT1
          BACKGROUND  = SWATCH0.TAB_BG_ON
          FOREGROUND  = SWATCH0.TAB_FG_ON
     ELSE
          FRAME_STYLE = FR_LIGHT0
          BACKGROUND  = SWATCH0.TAB_BG
          FOREGROUND  = SWATCH0.TAB_FG
     END IF
#ENDMACRO
#MACRO STYLE_BUTTON3()
     FRAME_COLOR = SWATCH0.BUTTON_FRM_OFF
     IF GDATA.state.HOVER  THEN FRAME_COLOR = SWATCH0.FRM_ACTIVE
     IF GDATA.state.ACTIVE THEN
          FRAME_STYLE = FR_LIGHT1
          FOREGROUND  = 0
     ELSE
          FRAME_STYLE = FR_LIGHT0
          IF GDATA.state.POWER THEN
               BACKGROUND = SWATCH0.BUTTON_BG_ACTIVE
               FOREGROUND = SWATCH0.BUTTON_FG_ACTIVE
          ELSEIF GDATA.state.POWER_LEVEL THEN
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          ELSE
               BACKGROUND = IIF(GDATA.CLR <> 0,GDATA.CLR,SWATCH0.BUTTON_BG)
               FOREGROUND = SWATCH0.BUTTON_FG
          END IF
     END IF
#ENDMACRO
#MACRO STYLE_SLIDEL()
     FRAME_COLOR = SWATCH0.BUTTON_FRM_OFF
     IF GDATA.state.HOVER  THEN FRAME_COLOR = SWATCH0.FRM_ACTIVE
     IF GDATA.state.ACTIVE THEN
          FRAME_STYLE = FR_LIGHT1
          BACKGROUND  = SWATCH0.BUTTON_BG_ACTIVE
          FOREGROUND  = 0
     ELSE
          FRAME_STYLE = FR_LIGHT0
          IF GDATA.state.POWER THEN
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          ELSE
               BACKGROUND = IIF(GDATA.CLR <> 0,GDATA.CLR,SWATCH0.BUTTON_BG)
               FOREGROUND = SWATCH0.BUTTON_FG
          END IF
     END IF
#ENDMACRO
#MACRO STYLE_FIELD_FRAME()
     FRAME_COLOR = SWATCH0.FRM_OFF
     IF GDATA.state.HOVER THEN FRAME_COLOR = SWATCH0.FRM_ACTIVE
     IF GDATA.state.ACTIVE THEN
          FRAME_COLOR = SWATCH0.FRM_ACTIVE
          FRAME_STYLE = FR_LIGHT1
     ELSE
          FRAME_STYLE = FR_LIGHT0
     END IF
#ENDMACRO

#MACRO STYLE_REC_POWER()
     FRAME_COLOR = SWATCH0.BUTTON_FRM_OFF
     IF GDATA.state.HOVER  THEN FRAME_COLOR = SWATCH0.FRM_ACTIVE     
     IF GDATA.state.ACTIVE THEN
          FRAME_STYLE = FR_LIGHT1
          BACKGROUND  = SWATCH0.BUTTON_BG_ACTIVE
          FOREGROUND  = SWATCH0.BUTTON_FG_ACTIVE
     ELSE
          FRAME_STYLE = FR_LIGHT0
          IF GDATA.state.POWER THEN
               BACKGROUND = SWATCH0.BUTTON_BG_REC
               FOREGROUND = RGB(255,255,255)
          ELSE
               BACKGROUND = SWATCH0.BUTTON_BG
               FOREGROUND = SWATCH0.BUTTON_BG_REC
          END IF
     END IF
#ENDMACRO

#MACRO STYLE_PLAY_POWER()
     FRAME_COLOR = SWATCH0.BUTTON_FRM_OFF
     IF GDATA.state.HOVER  THEN FRAME_COLOR = SWATCH0.FRM_ACTIVE     
     IF GDATA.state.ACTIVE THEN
          FRAME_STYLE = FR_LIGHT1
          BACKGROUND  = SWATCH0.BUTTON_BG_ACTIVE
          FOREGROUND  = SWATCH0.BUTTON_FG_ACTIVE
     ELSE
          FRAME_STYLE = FR_LIGHT0
          IF GDATA.state.POWER THEN
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = RGB(255,255,255)
          ELSE
               BACKGROUND = SWATCH0.BUTTON_BG
               FOREGROUND = SWATCH0.BUTTON_BG_ON
          END IF
     END IF
#ENDMACRO

#MACRO GLIST_VARIABLES()
     STATIC AS I32       old_list_size, old_order, old_vi, KS
     DIM AS I32          I,B,R,N, X,Y,W,Y0, list_size, NBL, start,finish, LINE_H,BAR_H, S
     DIM AS TXT          TMPSTR
#ENDMACRO
#MACRO GLIST_TOP_CODE(IMAGE_INDEX_OFFSET)
     'GRAPHIC INITIALIZATION
     KS     = INT(.1*ICON_SIZE)
     LINE_H = (GDATA.H - BORDER_SIZE * 2) / GDATA.TEXT.NB_LINES
     NBL    = GDATA.TEXT.NB_LINES
     S      = 1
     X      = GDATA.X + BORDER_SIZE
     Y      = GDATA.Y + BORDER_SIZE
     W      = GDATA.W - BORDER_SIZE - 2
     Y0     = .5*(LINE_H - GDATA.TEXT.FONT_SIZE)
     B      = IMAGE_INDEX_OFFSET
     'INDEX CALCULATIONS
     IF list_size < old_list_size THEN
          ceil(GDATA.TEXT.vi, list_size - GDATA.TEXT.nb_lines)
          floor(GDATA.TEXT.vi,0)
          Controls[ID]->text.vi = GDATA.text.vi '!!!
     END IF
     start  = IIF(GDATA.TEXT.reversed_index, list_size - GDATA.TEXT.vi - 1, GDATA.TEXT.vi)
     floor(start,0)
     finish = IIF(GDATA.TEXT.reversed_index, start - NBL + 1, GDATA.TEXT.vi + NBL - 1)
     ceil(finish,list_size-1)
     IF finish < start THEN 
          S = -1
          floor(finish,0)
          ceil(start,list_size-1)
     END IF
     'UPDATE CHECK
     IF old_order     <> GDATA.TEXT.reversed_index OR _
        old_list_size <> list_size OR _
        old_vi        <> GDATA.TEXT.vi THEN GDATA.TEXT.UPDATED = TRUE
#ENDMACRO
#MACRO GLIST_BOTTOM_CODE()
     old_list_size = list_size
     old_order     = GDATA.TEXT.reversed_index
     old_vi        = GDATA.TEXT.vi
     'TOP INDICATOR
     IF GDATA.TEXT.vi > 0 THEN
          X = GDATA.X + .5*(GDATA.W-32)
          Y = GDATA.Y + BORDER_SIZE
          FOR I = 0 TO BORDER_SIZE-1
               LINE DRAWING_DEST,(X,Y+I)-(X+31,Y+I),SWATCH0.FG,,&b1100110011001100
          NEXT I
     END IF
     'BOTTOM INDICATOR
     IF list_size - GDATA.TEXT.vi > NBL THEN
          X = GDATA.X + .5*(GDATA.W-32)
          Y = GDATA.Y + GDATA.H - BORDER_SIZE - 1
          FOR I = 0 TO BORDER_SIZE-1
               LINE DRAWING_DEST,(X,Y-I)-(X+31,Y-I),SWATCH0.FG,,&b1100110011001100
          NEXT I
     END IF
     'VERTICAL POSITION INDICATOR (RIGHT)
     IF NBL < list_size THEN
          IF START > FINISH THEN START = list_size - START - 1
          BAR_H = (GDATA.H - BORDER_SIZE * 2) *  NBL / list_size
          X = GDATA.X + GDATA.W - BORDER_SIZE - 1
          Y = GDATA.Y + (GDATA.H - BAR_H) * START / (list_size - NBL)
          LINE DRAWING_DEST,(X,Y)-(X-BORDER_SIZE+1,Y+BAR_H-1),WHITE,BF
     END IF
     STYLE_FLAT_FRAME(SWATCH0.LIST_FRM_OFF)
     DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, FRAME_COLOR)
#ENDMACRO

     
' GENERIC
DEC FCT gctrl_button          (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_state_button    (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_button2         (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_button_sicon    (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_button_sicon2   (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_static_layer    (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_img             (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_slidel          (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_stdpower        (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_link            (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_text_area       (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_label           (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_basic_frame     (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_basic_window    (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_trans_window    (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_sysbar_spacer   (BYREF AS _GDATA,AS I32)                                AS I32
'FRACTION-AID
DEC FCT gctrl_fa_value        (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_fa_binary       (BYREF AS _GDATA,AS I32)                                AS I32
'SYSTEM STATUS
DEC FCT gctrl_FRE             (BYREF AS _GDATA,AS I32)                                AS I32    'FREE RAM
DEC FCT gctrl_ALOAD           (BYREF AS _GDATA,AS I32)                                AS I32    'AUDIO WORKLOAD
DEC FCT gctrl_CLOAD           (BYREF AS _GDATA,AS I32)                                AS I32    'CONTROL WORKLOAD
DEC FCT gctrl_VLOAD           (BYREF AS _GDATA,AS I32)                                AS I32    'VIDEO WORKLOAD
'SYSTEM AUDIO
DEC FCT gctrl_mic_power       (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_mic_meter       (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_play_power      (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_play_meter      (BYREF AS _GDATA,AS I32)                                AS I32
'SYSTEM DIALOG
DEC FCT gctrl_ctrl_info       (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_msg_bar         (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_dialog_text     (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_text_field      (BYREF AS _GDATA,AS I32)                                AS I32
'TOOLS WINDOW
DEC FCT gctrl_module_infos    (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_param_list      (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_shape_list      (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_shape_graph     (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_filter_list     (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_melody_list     (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_sp_list         (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_filter_graph    (BYREF AS _GDATA,AS I32)                                AS I32
'BROWSER WINDOW
DEC FCT gctrl_list_sort       (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_file_drives     (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_system_list     (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_action_list     (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_file_list       (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_reference_list  (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_library_list    (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_sample_list     (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_sample_list_m   (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_MIDI_DEVS_list  (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_MIDICC_list     (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_midiin_display  (BYREF AS _GDATA,AS I32)                                AS I32
'KEYBOARDS
DEC FCT gctrl_kb_frame        (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_kb              (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_bb_frame        (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_bb              (BYREF AS _GDATA,AS I32)                                AS I32
'SETTINGS
DEC FCT gctrl_tuning_name     (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_tuning_scale    (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_tuning_keys     (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_tuning_sp       (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_tuning_sp_list  (BYREF AS _GDATA,AS I32)                                AS I32
'SYNTH
DEC FCT gctrl_module_group    (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_module_patch    (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_scope           (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_synth_plane     (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_synth_output    (BYREF AS _GDATA,AS I32)                                AS I32
DEC FCT gctrl_pp_display      (BYREF AS _GDATA,AS I32)                                AS I32
'DRAWINGS
DEC SUB DRAW_RAW_SCOPE(BYREF AS _GDATA,AS F32 PTR, AS I32)
DEC SUB DRAW_P2D_SCOPE(BYREF AS _GDATA,AS F32 PTR, AS I32)
DEC SUB DRAW_V2D_SCOPE(BYREF AS _GDATA,AS F32 PTR, AS I32)
DEC SUB DRAW_SPECTRUM(BYREF AS _GDATA,AS F32 PTR, AS I32)
'------------------------------------------------------------------------------------------------------------

'------------------------------------------------------------------------------------------------------------
'ICON OR TEXT + OFF COLOR
FUNCTION gctrl_button         (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM    AS IOS X,Y, W,H, OFFSET
     DIM    AS TXT TMPSTR
     'COLORS
     STYLE_BUTTON()
     PATCH_BG()
     'TEXT MANAGEMENT
     IF Controls[ID]->NB_IMAGES > 0 ANDALSO Controls[ID]->IMAGE[0] > 0 THEN  'IMAGE EXISTS
          'REPRINT?
          IF GDATA.TEXT.UPDATED THEN
               'CONTENT TYPE (ICON OR TEXT)
               IF NOT(GDATA.ICON.CHAR = 32) THEN
                  GDATA.TEXT.TEXT_WIDTH = GetFT_W(CHR(GDATA.ICON.CHAR),GDATA.ICON.FONT,GDATA.ICON.SIZE)
                  TEXT_FONT.Font_Hdl    = GDATA.ICON.FONT
                  TMPSTR                = CHR(GDATA.ICON.CHAR)
               ELSE
                  GDATA.TEXT.TEXT_WIDTH = GetTXT_W(GDATA.TEXT.CONTENT,MainFont,GDATA.TEXT.FONT_SIZE)
                  TEXT_FONT.Font_Hdl    = MainFont.Font_hdl
                  TMPSTR                = GDATA.TEXT.CONTENT
               END IF
               'CONTENT ALIGNMENT
               IMAGEINFO(Controls[ID]->IMAGE[0],W,H)
               CEIL(GDATA.TEXT.TEXT_WIDTH,W)
               Controls[ID]->text.text_width = GDATA.TEXT.TEXT_WIDTH '!!!
               X = 0
               Y = .5*(H - GDATA.text.font_size) + 1
               OFFSET = W - GDATA.TEXT.TEXT_WIDTH
               IF     GDATA.text.align = ALIGN_RIGHT THEN
                    X += OFFSET
               ELSEIF GDATA.text.align = ALIGN_CENTER THEN
                    X += .5*OFFSET
               END IF
               'BACKGROUND + PRINT
               LINE CONTROLS[ID]->IMAGE[0],(0,0)-(W-1,H-1),0,BF
               PrintFT(CONTROLS[ID]->IMAGE[0],X,Y,0,TMPSTR,TEXT_FONT.Font_Hdl,_
                  GDATA.TEXT.FONT_SIZE,FOREGROUND,GLYPH_ALPHA)
          END IF
          X = GDATA.X + BORDER_SIZE
          Y = GDATA.Y + BORDER_SIZE
          ACETATE_TRANSFER(Controls[ID]->IMAGE[0],X,Y)
     END IF
     DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, FRAME_COLOR)
     RETURN 0
END FUNCTION
'ICON OR TEXT + ON COLOR
FUNCTION gctrl_state_button         (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM    AS IOS X,Y, W,H, OFFSET
     DIM    AS TXT TMPSTR
     FRAME_COLOR = SWATCH0.BUTTON_FRM_OFF
     IF GDATA.state.HOVER    THEN FRAME_COLOR = SWATCH0.FRM_ON
     IF GDATA.state.ACTIVE   THEN
          FRAME_STYLE = FR_LIGHT1
          BACKGROUND  = SWATCH0.BUTTON_BG_ACTIVE
          FOREGROUND  = 0
     ELSE
          FRAME_STYLE = FR_LIGHT0
          IF GDATA.state.POWER THEN
               BACKGROUND = IIF(GDATA.CLR <> 0,GDATA.CLR,SWATCH0.BUTTON_BG_ON)
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          ELSE
               BACKGROUND = SWATCH0.BUTTON_BG
               FOREGROUND = SWATCH0.BUTTON_FG
          END IF
     END IF
     PATCH_BG()
     IF Controls[ID]->NB_IMAGES > 0 ANDALSO Controls[ID]->IMAGE[0] > 0 THEN  'IMAGE EXISTS
          'REPRINT?
          IF GDATA.TEXT.UPDATED THEN
               'CONTENT TYPE (ICON OR TEXT)
               IF NOT(GDATA.ICON.CHAR = 32) THEN
                  GDATA.TEXT.TEXT_WIDTH = GetFT_W(CHR(GDATA.ICON.CHAR),GDATA.ICON.FONT,GDATA.ICON.SIZE)
                  TEXT_FONT.Font_Hdl    = GDATA.ICON.FONT
                  TMPSTR                = CHR(GDATA.ICON.CHAR)
               ELSE
                  GDATA.TEXT.TEXT_WIDTH = GetTXT_W(GDATA.TEXT.CONTENT,MainFont,GDATA.TEXT.FONT_SIZE)
                  TEXT_FONT.Font_Hdl    = MainFont.Font_hdl
                  TMPSTR                = GDATA.TEXT.CONTENT
               END IF
               'CONTENT ALIGNMENT
               IMAGEINFO(Controls[ID]->IMAGE[0],W,H)
               CEIL(GDATA.TEXT.TEXT_WIDTH,W)
               Controls[ID]->text.text_width = GDATA.TEXT.TEXT_WIDTH '!!!
               X = 0
               Y = .5*(H - GDATA.text.font_size) + 1
               OFFSET = W - GDATA.TEXT.TEXT_WIDTH
               IF     GDATA.text.align = ALIGN_RIGHT THEN
                    X += OFFSET
               ELSEIF GDATA.text.align = ALIGN_CENTER THEN
                    X += .5*OFFSET
               END IF
               'BACKGROUND + PRINT
               LINE CONTROLS[ID]->IMAGE[0],(0,0)-(W-1,H-1),0,BF
               PrintFT(CONTROLS[ID]->IMAGE[0],X,Y,0,TMPSTR,TEXT_FONT.Font_Hdl,_
                  GDATA.TEXT.FONT_SIZE,FOREGROUND,GLYPH_ALPHA)
          END IF
          X = GDATA.X + BORDER_SIZE
          Y = GDATA.Y + BORDER_SIZE
          ACETATE_TRANSFER(Controls[ID]->IMAGE[0],X,Y)
     END IF
     DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, FRAME_COLOR)
     RETURN 0
END FUNCTION

'[ICON +] TEXT
FUNCTION gctrl_button2        (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM    AS IOS X,Y, X2,Y2, N, W,H, OFFSET

     'ICON (STATIC FOR NOW)
     N = 0
     X = GDATA.X + BORDER_SIZE
     Y = GDATA.Y + BORDER_SIZE
     IF NOT(GDATA.ICON.CHAR = 32) THEN
          IF Controls[ID]->NB_IMAGES > 0 ANDALSO Controls[ID]->IMAGE[0] > 0 THEN
               IMAGEINFO(Controls[ID]->IMAGE[0],W,H)
               X += BORDER_SIZE*3
               ACETATE_TRANSFER(Controls[ID]->IMAGE[0],X,Y)
               N  = 1
               X += W + BORDER_SIZE*2
          END IF
     END IF

     'TEXT MANAGEMENT     
     IF Controls[ID]->NB_IMAGES > N ANDALSO Controls[ID]->IMAGE[N] > 0 THEN  'IMAGE EXISTS
          'REPRINT?
          IF GDATA.TEXT.UPDATED THEN
               'TEXT ALIGNMENT
               GDATA.TEXT.TEXT_WIDTH = GetTXT_W(GDATA.TEXT.CONTENT,MainFont,GDATA.TEXT.FONT_SIZE)
               IMAGEINFO(Controls[ID]->IMAGE[N],W,H)
               IF N = 1 THEN W -= X
               CEIL(GDATA.TEXT.TEXT_WIDTH,W)
               Controls[ID]->text.text_width = GDATA.TEXT.TEXT_WIDTH '!!!
               X2 = 0
               Y2 = .5*(H - GDATA.text.font_size) + 1
               OFFSET = W - GDATA.TEXT.TEXT_WIDTH
               IF     GDATA.text.align = ALIGN_RIGHT THEN
                    X2 += OFFSET
               ELSEIF GDATA.text.align = ALIGN_CENTER THEN
                    X2 += .5*OFFSET
               END IF
               'BACKGROUND + PRINT
               LINE CONTROLS[ID]->IMAGE[N],(0,0)-(W-1,H-1),0,BF
               PrintFT(CONTROLS[ID]->IMAGE[N],X2,Y2,0,GDATA.TEXT.CONTENT,MainFont.Font_Hdl,_
                  GDATA.TEXT.FONT_SIZE,FOREGROUND,GLYPH_ALPHA)
          END IF
          ACETATE_TRANSFER(Controls[ID]->IMAGE[N],X,Y)
     END IF

     DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, FRAME_COLOR)

     RETURN 0
END FUNCTION

'BUTTON BUT WITH DIFFERENT COLOR DISPLAY METHOD
FUNCTION gctrl_button3        (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM    AS IOS X,Y, W,H, OFFSET
     DIM    AS TXT TMPSTR
     'COLORS
     STYLE_BUTTON3()
     PATCH_BG()

     'TEXT MANAGEMENT
     IF Controls[ID]->NB_IMAGES > 0 ANDALSO Controls[ID]->IMAGE[0] > 0 THEN  'IMAGE EXISTS
          'REPRINT?
          IF GDATA.TEXT.UPDATED THEN
               'CONTENT TYPE (ICON OR TEXT)
               IF NOT(GDATA.ICON.CHAR = 32) THEN
                  GDATA.TEXT.TEXT_WIDTH = GetFT_W(CHR(GDATA.ICON.CHAR),GDATA.ICON.FONT,GDATA.ICON.SIZE)
                  TEXT_FONT.Font_Hdl    = GDATA.ICON.FONT
                  TMPSTR                = CHR(GDATA.ICON.CHAR)
               ELSE
                  GDATA.TEXT.TEXT_WIDTH = GetTXT_W(GDATA.TEXT.CONTENT,MainFont,GDATA.TEXT.FONT_SIZE)
                  TEXT_FONT.Font_Hdl    = MainFont.Font_hdl
                  TMPSTR                = GDATA.TEXT.CONTENT
               END IF
               'CONTENT ALIGNMENT
               IMAGEINFO(Controls[ID]->IMAGE[0],W,H)
               CEIL(GDATA.TEXT.TEXT_WIDTH,W)
               Controls[ID]->text.text_width = GDATA.TEXT.TEXT_WIDTH '!!!
               X = 0
               Y = .5*(H - GDATA.text.font_size) + 1
               OFFSET = W - GDATA.TEXT.TEXT_WIDTH
               IF     GDATA.text.align = ALIGN_RIGHT THEN
                    X += OFFSET
               ELSEIF GDATA.text.align = ALIGN_CENTER THEN
                    X += .5*OFFSET
               END IF
               'BACKGROUND + PRINT
               LINE CONTROLS[ID]->IMAGE[0],(0,0)-(W-1,H-1),0,BF
               PrintFT(CONTROLS[ID]->IMAGE[0],X,Y,0,TMPSTR,TEXT_FONT.Font_Hdl,_
                  GDATA.TEXT.FONT_SIZE,FOREGROUND,GLYPH_ALPHA)
          END IF
          X = GDATA.X + BORDER_SIZE
          Y = GDATA.Y + BORDER_SIZE
          ACETATE_TRANSFER(Controls[ID]->IMAGE[0],X,Y)
     END IF
     DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, FRAME_COLOR)
     RETURN 0
END FUNCTION

FUNCTION gctrl_button_tab     (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM    AS IOS X,Y, W,H, OFFSET
     DIM    AS TXT TMPSTR
     'COLORS

     STYLE_BUTTON_TAB()
     PATCH_BG()

     'TEXT MANAGEMENT
     IF Controls[ID]->NB_IMAGES > 0 ANDALSO Controls[ID]->IMAGE[0] > 0 THEN  'IMAGE EXISTS
          'REPRINT?
          IF GDATA.TEXT.UPDATED THEN
               'CONTENT TYPE (ICON OR TEXT)
               IF NOT(GDATA.ICON.CHAR = 32) THEN
                  GDATA.TEXT.TEXT_WIDTH = GetFT_W(CHR(GDATA.ICON.CHAR),GDATA.ICON.FONT,GDATA.ICON.SIZE)
                  TEXT_FONT.Font_Hdl    = GDATA.ICON.FONT
                  TMPSTR               = CHR(GDATA.ICON.CHAR)
               ELSE
                  GDATA.TEXT.TEXT_WIDTH = GetTXT_W(GDATA.TEXT.CONTENT,MainFont,GDATA.TEXT.FONT_SIZE)
                  TEXT_FONT.Font_Hdl    = MainFont.Font_hdl
                  TMPSTR               = GDATA.TEXT.CONTENT
               END IF
               'CONTENT ALIGNMENT
               IMAGEINFO(Controls[ID]->IMAGE[0],W,H)
               CEIL(GDATA.TEXT.TEXT_WIDTH,W)
               Controls[ID]->text.text_width = GDATA.TEXT.TEXT_WIDTH '!!!
               X = 0
               Y = .5*(H - GDATA.text.font_size) + 1
               OFFSET = W - GDATA.TEXT.TEXT_WIDTH
               IF     GDATA.text.align = ALIGN_RIGHT THEN
                    X += OFFSET
               ELSEIF GDATA.text.align = ALIGN_CENTER THEN
                    X += .5*OFFSET
               END IF
               'BACKGROUND + PRINT
               LINE CONTROLS[ID]->IMAGE[0],(0,0)-(W-1,H-1),0,BF
               PrintFT(CONTROLS[ID]->IMAGE[0],X,Y,0,TMPSTR,TEXT_FONT.Font_Hdl,_
                  GDATA.TEXT.FONT_SIZE,FOREGROUND,GLYPH_ALPHA)
          END IF
          X = GDATA.X + BORDER_SIZE
          Y = GDATA.Y + BORDER_SIZE
          ACETATE_TRANSFER(Controls[ID]->IMAGE[0],X,Y)
     END IF
     DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, FRAME_COLOR)
     RETURN 0
END FUNCTION

FUNCTION gctrl_button_sicon   (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     'SIMPLE BUTTON THAT DRAWS LAYER #I
     DIM AS IOS I,X,Y
     STYLE_BUTTON()
     PATCH_BG()
     
     I = GDATA.TEXT.SI
     FLOOR(I,0)
     CEIL(I,Controls[ID]->NB_IMAGES-1)
     
     X = GDATA.X + BORDER_SIZE
     Y = GDATA.Y + BORDER_SIZE
     ACETATE_TRANSFER(Controls[ID]->IMAGE[I],X,Y)
     DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, FRAME_COLOR)
     
     RETURN 0
END FUNCTION

FUNCTION gctrl_button_sicon2  (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM    AS IOS X,Y, W,H, N, OFFSET
     DIM    AS TXT TMPSTR
     'COLORS
     IF GDATA.STATE.ACTIVE THEN _
        LINE DRAWING_DEST,(GDATA.X,GDATA.Y)-(GDATA.X+GDATA.W-1,GDATA.Y+GDATA.H-1),SWATCH0.BUTTON_BG_ACTIVE,BF

     'ICON
     N = GDATA.TEXT.SI
     FLOOR(N,0)
     CEIL(N,Controls[ID]->NB_IMAGES-1)
     IF Controls[ID]->NB_IMAGES > 0 ANDALSO Controls[ID]->IMAGE[N] > 0 THEN  'IMAGE EXISTS
          X = GDATA.X + BORDER_SIZE
          Y = GDATA.Y + BORDER_SIZE
          ACETATE_TRANSFER(Controls[ID]->IMAGE[N],X,Y)
     END IF
     
     IF GDATA.state.HOVER THEN DrawFrame(GDATA,FR_SOLID, BORDER_SIZE, WHITE)
     RETURN 0
END FUNCTION

FUNCTION gctrl_static_layer   (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM    AS I32 X,Y
     X = GDATA.X + BORDER_SIZE
     Y = GDATA.Y + BORDER_SIZE
     IF Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[0] > 0 THEN 
          ACETATE_TRANSFER(Controls[ID]->IMAGE[0],X,Y)
     END IF
     RETURN 0
END FUNCTION

FUNCTION gctrl_img            (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM AS IOS METHOD,X,Y
     X = GDATA.X
     Y = GDATA.Y
     METHOD = Controls[ID]->INDEX
     SELECT CASE METHOD
     CASE PUT_SET
          IF Controls[ID]->NB_IMAGES > 0 ANDALSO Controls[ID]->IMAGE[0] > 0 THEN _
             PUT DRAWING_DEST,(X,Y), Controls[ID]->IMAGE[0], PSET
     CASE PUT_ADD
          IF Controls[ID]->NB_IMAGES > 0 ANDALSO Controls[ID]->IMAGE[0] > 0 THEN _
             PUT DRAWING_DEST,(X,Y), Controls[ID]->IMAGE[0], ADD
     CASE PUT_ALPHA
          IF Controls[ID]->NB_IMAGES > 0 ANDALSO Controls[ID]->IMAGE[0] > 0 THEN 
               ACETATE_TRANSFER(Controls[ID]->IMAGE[0],X,Y)
          END IF
     END SELECT
     RETURN 0
END FUNCTION

FUNCTION gctrl_SLIDEL         (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM AS I32 R
     DIM AS IOS X,Y, W,H, N, OFFSET
     DIM AS TXT TMPSTR
     'COLORS
     STYLE_SLIDEL()
     PATCH_BG()
     'HIGHLIGHT CLICKING ZONES
     IF GDATA.TEXT.HI > 0 THEN
          DIM AS I32 X0,X1,Y0,Y1,Z
          IF GDATA.H <= GDATA.W THEN
               Z = 1.8*GDATA.TEXT.FONT_SIZE
               CEIL(Z,.5*GDATA.W)
               OFFSET = IIF(GDATA.TEXT.HI=1,BORDER_SIZE,GDATA.W-Z)
               X0 = GDATA.X+OFFSET
               Y0 = GDATA.Y+BORDER_SIZE
               X1 = GDATA.X+Z+OFFSET-BORDER_SIZE-1
               Y1 = GDATA.Y+GDATA.H-BORDER_SIZE-1
          ELSE
               Z = 1.8*GDATA.TEXT.FONT_SIZE
               CEIL(Z,.5*GDATA.H)
               OFFSET = IIF(GDATA.TEXT.HI=1,BORDER_SIZE,GDATA.H-Z)
               X0 = GDATA.X+BORDER_SIZE
               Y0 = GDATA.Y+OFFSET
               X1 = GDATA.X+GDATA.W-BORDER_SIZE-1
               Y1 = GDATA.Y+Z+OFFSET-BORDER_SIZE-1
          END IF
          LINE DRAWING_DEST,(X0,Y0)-(X1,Y1),SWATCH0.BUTTON_BG_ACTIVE,BF
     END IF
     'TEXT MANAGEMENT
     IF Controls[ID]->NB_IMAGES > 0 ANDALSO Controls[ID]->IMAGE[0] > 0 THEN  'IMAGE EXISTS
          'REPRINT?
          IF GDATA.TEXT.UPDATED THEN
               'CONTENT TYPE (ICON OR TEXT)
               IF NOT(GDATA.ICON.CHAR = 32) THEN
                  GDATA.TEXT.TEXT_WIDTH = GetFT_W(CHR(GDATA.ICON.CHAR),GDATA.ICON.FONT,GDATA.ICON.SIZE)
                  TEXT_FONT.Font_Hdl    = GDATA.ICON.FONT
                  TMPSTR                = CHR(GDATA.ICON.CHAR)
               ELSE
                  GDATA.TEXT.TEXT_WIDTH = GetTXT_W(GDATA.TEXT.CONTENT,MainFont,GDATA.TEXT.FONT_SIZE)
                  TEXT_FONT.Font_Hdl    = MainFont.Font_hdl
                  TMPSTR                = GDATA.TEXT.CONTENT
               END IF
               'CONTENT ALIGNMENT
               IMAGEINFO(Controls[ID]->IMAGE[0],W,H)
               CEIL(GDATA.TEXT.TEXT_WIDTH,W)
               Controls[ID]->text.text_width = GDATA.TEXT.TEXT_WIDTH '!!!
               X = 0
               Y = .5*(H - GDATA.text.font_size) + 1
               OFFSET = W - GDATA.TEXT.TEXT_WIDTH
               IF     GDATA.text.align = ALIGN_RIGHT THEN
                    X += OFFSET
               ELSEIF GDATA.text.align = ALIGN_CENTER THEN
                    X += .5*OFFSET 
               END IF
               'BACKGROUND + PRINT
               LINE CONTROLS[ID]->IMAGE[0],(0,0)-(W-1,H-1),0,BF
               PrintFT(CONTROLS[ID]->IMAGE[0],X,Y,0,TMPSTR,TEXT_FONT.Font_Hdl,_
                  GDATA.TEXT.FONT_SIZE,FOREGROUND,GLYPH_ALPHA)
          END IF
          X = GDATA.X + BORDER_SIZE
          Y = GDATA.Y + BORDER_SIZE
          IF GDATA.H < GDATA.W THEN X = GDATA.X + BORDER_SIZE + ICON_SIZE
          ACETATE_TRANSFER(Controls[ID]->IMAGE[0],X,Y)
     END IF
     'DRAW ARROWS LAYER, FRAME
     IF Controls[ID]->NB_IMAGES > 1 THEN
          ACETATE_TRANSFER(Controls[ID]->IMAGE[1],GDATA.X,GDATA.Y)
     END IF
     DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, FRAME_COLOR)
     RETURN R
END FUNCTION

FUNCTION gctrl_stdpower      (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM    AS I32  X,Y
     'COLORS
     STYLE_BUTTON()     
     PATCH_BG()
     'TEXT OR ICON, FRAME
     IF CONTROLS[ID]->NB_IMAGES > 0 ANDALSO CONTROLS[ID]->IMAGE[0] > 0 THEN _
        PUT DRAWING_DEST, (GDATA.X+BORDER_SIZE+1,GDATA.Y+BORDER_SIZE+1), Controls[ID]->IMAGE[0],ADD
     DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, FRAME_COLOR)
     RETURN 0
END FUNCTION

FUNCTION gctrl_link           (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM AS IOS     X,Y, N
     IF (Controls[ID]->NB_IMAGES > 0) ANDALSO (Controls[ID]->IMAGE[0] > 0) THEN
          X = GDATA.X + BORDER_SIZE
          Y = GDATA.Y + BORDER_SIZE
          N = 0
          IF GDATA.STATE.HOVER THEN
               BACKGROUND = SWATCH0.BUTTON_BG_ACTIVE
               PATCH_BG()
               N = 1
          END IF
          PUT DRAWING_DEST,(X,Y), Controls[ID]->IMAGE[N],ALPHA
     END IF
     RETURN 0
END FUNCTION
FUNCTION gctrl_basic_frame    (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DrawFrame(GDATA,FR_SOLID, BORDER_SIZE, SWATCH0.LIST_FRM_OFF)
     RETURN 0
END FUNCTION
FUNCTION gctrl_basic_window   (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     BACKGROUND = GDATA.CLR
     PATCH_BG()
     DrawFrame(GDATA,FR_SOLID, BORDER_SIZE, SWATCH0.FRM_OFF)
     RETURN 0
END FUNCTION
FUNCTION gctrl_trans_window   (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     BACKGROUND = GDATA.CLR
     PUT DRAWING_DEST,(GDATA.X,GDATA.Y),Controls[ID]->IMAGE[0],ALPHA
     DrawFrame(GDATA,FR_SOLID, BORDER_SIZE, SWATCH0.FRM_OFF)
     RETURN 0
END FUNCTION

FUNCTION gctrl_text_area      (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM AS I32     R
     DIM AS IOS     X,Y, W,H,H1, nb_lines
     IF Controls[ID]->NB_IMAGES THEN
          'TEXT UPDATE
          nb_lines = GDATA.TEXT.nb_lines
          IF GDATA.TEXT.UPDATED THEN
               'COUNT LINES
               W = GDATA.W - ABS(GDATA.TEXT.LM) - ABS(GDATA.TEXT.RM) - BORDER_SIZE - BORDER_SIZE
               nb_lines = CountTextLines(GDATA.TEXT.CONTENT, MainFont, W, GDATA.TEXT.FONT_SIZE)
               Controls[ID]->TEXT.nb_lines = nb_lines '!!!
               'RESIZE IMAGE 0
               H = nb_lines * GDATA.TEXT.FONT_SIZE + 2
               Controls[ID]->SET_IMAGE(0,W,H)
               'PRINT TEXT
               R = PrintText(Controls[ID]->IMAGE[0],0,0,W,H,GDATA.TEXT.CONTENT,MainFont,_
                   GDATA.TEXT.FONT_SIZE,GDATA.TEXT.FONT_CLR)
          END IF
          'SLICING
          IMAGEINFO(Controls[ID]->IMAGE[0],W,H)
          H1 = GDATA.H - ABS(GDATA.TEXT.TM) - ABS(GDATA.TEXT.BM) - BORDER_SIZE - BORDER_SIZE
          CEIL(GDATA.TEXT.VPX0,H-H1)
          'DRAW TEXT ACETATE
          X = GDATA.X + BORDER_SIZE + GDATA.TEXT.LM
          Y = GDATA.Y + BORDER_SIZE + GDATA.TEXT.TM
          ACETATE_TRANSFER_S(Controls[ID]->IMAGE[0],X,Y,0,W-1,GDATA.TEXT.VPX0,GDATA.TEXT.VPX0+H1-1)
     END IF
     STYLE_FLAT_FRAME(SWATCH0.FRM_OFF)
     DrawFrame(GDATA,FRAME_STYLE,BORDER_SIZE,FRAME_COLOR)
     RETURN 0
END FUNCTION

FUNCTION gctrl_label          (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM AS IOS     X,Y, W,H, OFFSET
     IF (Controls[ID]->NB_IMAGES > 0) ANDALSO (Controls[ID]->IMAGE[0] > 0) THEN
          'TEXT UPDATE
          IF GDATA.TEXT.UPDATED THEN
               'TEXT ALIGNMENT
               GDATA.TEXT.TEXT_WIDTH = GetTXT_W(GDATA.TEXT.CONTENT,MainFont,GDATA.TEXT.FONT_SIZE)
               IMAGEINFO(Controls[ID]->IMAGE[0],W,H)
               CEIL(GDATA.TEXT.TEXT_WIDTH,W)
               Controls[ID]->text.text_width = GDATA.TEXT.TEXT_WIDTH '!!!
               X      = 0
               Y      = .5*(H - GDATA.text.font_size)
               OFFSET = W - GDATA.TEXT.TEXT_WIDTH
               IF     GDATA.text.align = ALIGN_RIGHT THEN
                    X += OFFSET
               ELSEIF GDATA.text.align = ALIGN_CENTER THEN
                    X += .5*OFFSET
               END IF
               'PATCH BG AND PRINT TEXT
               LINE Controls[ID]->IMAGE[0],(0,0)-(W-1,H-1),0,BF
               PrintFT(Controls[ID]->IMAGE[0],X,Y,0,GDATA.TEXT.CONTENT,MainFont.Font_hdl,_
                       GDATA.TEXT.FONT_SIZE,GDATA.TEXT.FONT_CLR)
          END IF
          X = GDATA.X + BORDER_SIZE
          Y = GDATA.Y + BORDER_SIZE
          ACETATE_TRANSFER(Controls[ID]->IMAGE[0],X,Y)
     END IF
     RETURN 0
END FUNCTION
'FRACTION-AID
FUNCTION gctrl_fa_value       (BYREF GDATA AS _GDATA, ID AS I32)       AS I32
     DIM AS FRACTIONAID.DATA  PTR FA_PTR0, FA_PTR
     DIM AS I32               DIGIT_W, I,J,R,X,Y,W,TXT_W, LM, FT, TEXT_SIZE
     DIM AS IOS               REPRINT

     STYLE_FLAT_FRAME(SWATCH0.FRM_OFF)
     PATCH_BG()
     BACKGROUND  = GDATA.CLR
     FOREGROUND  = GDATA.TEXT.FONT_CLR
     
     FA_PTR0 = GDATA.DATA
     IF FA_PTR0 > 0 THEN
          'REFRESH VALUE?
          DIM AS SOUNDRA.MODULE PTR MOD_PTR = SOUNDRA.SELECTED_MODULE
          DIM AS I32            PID
          IF MOD_PTR > 0 ANDALSO MOD_PTR->SELECTED_PID > -1 THEN
               PID = MOD_PTR->SELECTED_PID
               IF (@MOD_PTR->PARAM(PID).FA = FA_PTR0) ANDALSO (MOD_PTR->PARAM(PID).DO_REFRESH_FA = TRUE) THEN
                    DIM AS F32 V = MOD_PTR->PARAM(PID).PortValue * MOD_PTR->PARAM(PID).FACTOR
                    MOD_PTR->PARAM(PID).DO_REFRESH_FA = FALSE
                    MUTEXLOCK   FA_PTR0->MUTEX
                    FA_PTR0->IMPORT_VALUE(V)
                    MUTEXUNLOCK FA_PTR0->MUTEX
               END IF
          END IF
          'COPY DATA
          FA_PTR  = NEW FRACTIONAID.DATA
          MUTEXLOCK   FA_PTR0->MUTEX
          REPRINT = FA_PTR0->REPRINT
          FA_PTR0->REPRINT = FALSE
          FT = FA_PTR0->FORM_TYPE
          IF FT <> BINARY_INT THEN
               I     = FA_PTR0->NB_SLOTS-1
               TXT_W = FA_PTR0->SLOTS(I).X + FA_PTR0->SLOTS(I).W
               LM    = .5*(FA_PTR0->W - TXT_W)
               FLOOR(LM,0)
          END IF
          FA_PTR0->LM = LM
          *FA_PTR  = *FA_PTR0
          MUTEXUNLOCK FA_PTR0->MUTEX
          'PROCESS DATA
          IF FT = BINARY_INT THEN 'BOXES
               DIM AS I32  SX = (GDATA.W-BORDER_SIZE-BORDER_SIZE)/SOUNDRA.BIN_LINE_SIZE, _
                           SY = (GDATA.H-BORDER_SIZE-BORDER_SIZE)*.5
               DIM AS UI32 CLR,VI
               'DRAW RECTANGLES
               X  = 0
               Y  = 0
               VI = CULNG(ABS(FA_PTR->VALUE.V))
               FOR I = 0 TO SOUNDRA.BIN_LEN_MAX-1
                    CLR = IIF((VI AND 1) = 1,SWATCH0.BUTTON_BG_ON,SWATCH0.BUTTON_BG)
                    LINE Controls[ID]->IMAGE[0],(X,Y)-(X+SX-1,Y+SY-1),CLR,BF
                    LINE Controls[ID]->IMAGE[0],(X,Y)-(X+SX-1,Y+SY-1),SWATCH0.FRM_OFF,B
                    IF I = GDATA.TEXT.SI THEN _
                       LINE Controls[ID]->IMAGE[0],(X,Y)-(X+SX-1,Y+SY-1),SWATCH0.FRM_ON,B
                    X += SX
                    IF I = SOUNDRA.BIN_LINE_SIZE-1 THEN
                         X  = 0
                         Y += SY
                    END IF
                    VI SHR= 1
               NEXT I
          ELSE 'TEXT
               IF REPRINT = TRUE THEN
                    TEXT_SIZE = FA_PTR->FONT_SIZE
                    Y = .5*(FA_PTR->H - TEXT_SIZE) + 1
                    LINE Controls[ID]->IMAGE[0],(0,0)-(FA_PTR->W-1,FA_PTR->H-1),0,BF 'BG
                    'PRINT SLOTS
                    FOR I = 0 TO FA_PTR->NB_SLOTS-1
                         X = FA_PTR->SLOTS(I).X
                         R = PrintFT(Controls[ID]->IMAGE[0],X,Y,0,FA_PTR->SLOTS(I).TEXT,_
                                MainFont.Font_hdl,TEXT_SIZE,FOREGROUND)
                         IF R < 0 THEN EXIT FOR
                    NEXT I
               END IF
               'HIGHLIGH ACTIVE ZONE
               I = GDATA.TEXT.si
               IF (I > -1) AND (I < FA_PTR->NB_SLOTS) THEN
                    X = GDATA.X + BORDER_SIZE + FA_PTR->SLOTS(I).X + LM
                    W = FA_PTR->SLOTS(I).W
                    LINE DRAWING_DEST, (X,GDATA.Y)-(X+W-1,GDATA.Y+GDATA.H-1),SWATCH0.BUTTON_BG_ACTIVE,BF
               END IF
               IF R < 0 THEN RETURN R
          END IF
     ELSE
          LINE Controls[ID]->IMAGE[0],(0,0)-(GDATA.W-BORDER_SIZE*2-1,GDATA.H-BORDER_SIZE*2-1),0,BF
     END IF
     
     'DRAW IMAGE
     X = GDATA.X + BORDER_SIZE + LM
     Y = GDATA.Y + BORDER_SIZE
     IF Controls[ID]->NB_IMAGES THEN
        ACETATE_TRANSFER(Controls[ID]->IMAGE[0],X,Y)
     END IF
     DrawFrame(GDATA,FRAME_STYLE,BORDER_SIZE,FRAME_COLOR)
     IF FA_PTR > 0 THEN DELETE FA_PTR
     RETURN 0
END FUNCTION

' SYSTEM BAR
FUNCTION gctrl_FRE            (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM       AS I32         X,Y
     STATIC    AS F64         CHRONO,DT
     STATIC    AS IOS         FR
     STATIC    AS F32         FR2

     'TIMING (UPDATE EVERY SECOND)
     GETDT(DT,CHRONO)
     IF DT >= 1 THEN
          CHRONO = TIMER
          FR     = FRE / 1048576 'MB
          IF FR > 999 THEN
               FR2 = FR / 1024
               FR2 = .01*INT(100*FR2)
               GDATA.TEXT.CONTENT = STR(FR2) & " GB"
          ELSE
               FR2 = FR
               FR2 = INT(FR2)
               GDATA.TEXT.CONTENT = STR(FR2) & " MB"
          END IF
     ELSE
          GDATA.TEXT.UPDATED = FALSE
     END IF
     
     'BACKGROUND
     IF FR < 128\1048576 THEN
          BACKGROUND = RGB(200,0,0)
     ELSEIF FR < 100 THEN
          BACKGROUND = RGB(200,100,0)
     ELSEIF FR < 500 THEN
          BACKGROUND = RGB(215,170,20)
     ELSE
          BACKGROUND = SWATCH0.BUTTON_BG_ON
     END IF
     PATCH_BG()
     'TEXT MANAGEMENT (FIXED IMAGE WIDTH, CENTERED)
     IF Controls[ID]->NB_IMAGES > 0 ANDALSO Controls[ID]->IMAGE[0] > 0 THEN  'IMAGE EXISTS
          'REPRINT?
          IF GDATA.TEXT.UPDATED THEN
               DIM AS IOS W,H
               GDATA.TEXT.TEXT_WIDTH = GetTXT_W(GDATA.TEXT.CONTENT,MainFont,GDATA.TEXT.FONT_SIZE)
               IMAGEINFO(Controls[ID]->IMAGE[0],W,H)
               CEIL(GDATA.TEXT.TEXT_WIDTH,W)
               Controls[ID]->text.text_width = GDATA.TEXT.TEXT_WIDTH '!!!
               X = .5*(W - GDATA.TEXT.TEXT_WIDTH)
               Y = .5*(H - GDATA.text.font_size) + 1
               'PATCH BG (CONTROL WIDTH) AND PRINT TEXT
               LINE CONTROLS[ID]->IMAGE[0],(0,0)-(W-1,H-1),0,BF
               PrintFT(CONTROLS[ID]->IMAGE[0],X,Y,0,GDATA.TEXT.CONTENT,MainFont.Font_hdl,_
                       GDATA.TEXT.FONT_SIZE,GDATA.TEXT.FONT_CLR,GLYPH_ADD)
          END IF
          'CENTER TEXT
          X = GDATA.X + BORDER_SIZE
          Y = GDATA.Y + BORDER_SIZE
          PUT DRAWING_DEST,(X,Y), Controls[ID]->IMAGE[0], ADD
     END IF
     
     STYLE_FLAT_FRAME(SWATCH0.FRM_OFF)
     DrawFrame(GDATA,FRAME_STYLE,BORDER_SIZE,FRAME_COLOR)
     RETURN 0
END FUNCTION

FUNCTION gctrl_WLOAD          (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM       AS I32         X,Y
     DIM       AS TXT         TMPSTR
     STATIC    AS F32         WLOAD_P
     STATIC    AS F64         T

     'INFO - REFRESH THRICE A SECOND
     IF TIMER - T > .33 THEN
          T = TIMER
          WLOAD_P = WLOAD
          WLOAD_P = .1*INT(1000*WLOAD_P)
          '¤¤¤#274: "The current audio workload is "
          TMPSTR = LNG_SET_EXT(274,"The current audio workload is ")
          TMPSTR &= STR(WLOAD_P) & " %."
          MUTEXLOCK   MT_CTRL_INFO
          Controls[ID]->CTRL_INFO = TMPSTR
          MUTEXUNLOCK MT_CTRL_INFO
     END IF
     
     'COLOR
     IF    WLOAD_P = 0        THEN                     'Standby
          BACKGROUND = SWATCH0.WINDOW_BG
     ELSEIF WLOAD_P < 10      THEN                     'LIGHT
          BACKGROUND = SWATCH0.TAB_BG_ON
     ELSEIF WLOAD_P < 33      THEN                     'ACTIVE
          BACKGROUND = SWATCH0.BUTTON_BG_ON
     ELSEIF WLOAD_P < 66      THEN                     'HEAVY
          BACKGROUND = SWATCH0.BUTTON_BG_ACTIVE
     ELSEIF WLOAD_P < 90      THEN                     'VERY HEAVY
          BACKGROUND = SWATCH0.BUTTON_BG_ACTIVE
     ELSEIF WLOAD_P < 100     THEN                     'MIGHT OVERRUN
          BACKGROUND = SWATCH0.BUTTON_BG_REC
     ELSE
          BACKGROUND = MAGENTA
     END IF
     
     'BG + TEXT
     PATCH_BG()
     X = GDATA.X + BORDER_SIZE
     Y = GDATA.Y + BORDER_SIZE
     IF CONTROLS[ID]->NB_IMAGES > 0 ANDALSO CONTROLS[ID]->IMAGE[0] > 0 THEN _
        PUT DRAWING_DEST, (X,Y), Controls[ID]->IMAGE[0],ADD

     STYLE_FLAT_FRAME(SWATCH0.FRM_OFF)
     DrawFrame(GDATA,FRAME_STYLE,BORDER_SIZE,FRAME_COLOR)

     RETURN 0
END FUNCTION
FUNCTION gctrl_ALOAD          (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM       AS I32         X,Y
     DIM       AS TXT         TMPSTR
     STATIC    AS I32         ALOAD2
     STATIC    AS F64         T
     
     'INFO - REFRESH THRICE A SECOND
     IF TIMER - T > .33 THEN
          T = TIMER
          ALOAD2 = ALOAD
          '¤¤¤#275: "The current audio loop speed is "
          TMPSTR = LNG_SET_EXT(275,"The current audio loop speed is ")
          TMPSTR &= STR(ALOAD2) & " Hz."
          MUTEXLOCK   MT_CTRL_INFO
          Controls[ID]->CTRL_INFO = TMPSTR
          MUTEXUNLOCK MT_CTRL_INFO
     END IF
     
     'COLOR
     IF     ALOAD2 < 1000                     THEN     'STANDBY
          BACKGROUND = SWATCH0.WINDOW_BG
     ELSEIF ALOAD2 < SETTINGS.SAMPLE_RATE     THEN     'VERY SLOW
          BACKGROUND = SWATCH0.BUTTON_BG_REC
     ELSEIF ALOAD2 < SETTINGS.SAMPLE_RATE * 2 THEN     'SLOW
          BACKGROUND = SWATCH0.BUTTON_BG_ACTIVE
     ELSEIF ALOAD2 < SETTINGS.SAMPLE_RATE * 4 THEN     'OK
          BACKGROUND = SWATCH0.BUTTON_BG_ON
     ELSE
          BACKGROUND = SWATCH0.TAB_BG_ON
     END IF
     
     'BG + TEXT
     PATCH_BG()
     X = GDATA.X + BORDER_SIZE
     Y = GDATA.Y + BORDER_SIZE
     IF CONTROLS[ID]->NB_IMAGES > 0 ANDALSO CONTROLS[ID]->IMAGE[0] > 0 THEN _
        PUT DRAWING_DEST, (X,Y), Controls[ID]->IMAGE[0],ADD

     STYLE_FLAT_FRAME(SWATCH0.FRM_OFF)
     DrawFrame(GDATA,FRAME_STYLE,BORDER_SIZE,FRAME_COLOR)
     
     RETURN 0
END FUNCTION
FUNCTION gctrl_VLOAD          (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     STATIC    AS I32         VLOAD
     DIM       AS TXT         TMPSTR
     DIM       AS I32         X,Y
     
     'INFO 
     VLOAD = G_FPS
     '¤¤¤#276: "The current video framerate is "
     TMPSTR = LNG_SET_EXT(276,"The current video framerate is ")
     TMPSTR &= STR(VLOAD) & " Hz."
     MUTEXLOCK   MT_CTRL_INFO
     Controls[ID]->CTRL_INFO = TMPSTR
     MUTEXUNLOCK MT_CTRL_INFO
     
     'COLOR
     IF     VLOAD >  TARGET_FPS+9 THEN
          BACKGROUND = SWATCH0.TAB_BG_ON
     ELSEIF VLOAD >  TARGET_FPS-9 THEN
          BACKGROUND = SWATCH0.BUTTON_BG_ON
     ELSEIF VLOAD >  .5*TARGET_FPS THEN
          BACKGROUND = SWATCH0.BUTTON_BG_ACTIVE
     ELSE
          BACKGROUND = SWATCH0.BUTTON_BG_REC
     END IF
     
     'BG + TEXT
     PATCH_BG()
     X = GDATA.X + BORDER_SIZE
     Y = GDATA.Y + BORDER_SIZE
     IF CONTROLS[ID]->NB_IMAGES > 0 ANDALSO CONTROLS[ID]->IMAGE[0] > 0 THEN _
        PUT DRAWING_DEST, (X,Y), Controls[ID]->IMAGE[0],ADD

     STYLE_FLAT_FRAME(SWATCH0.FRM_OFF)
     DrawFrame(GDATA,FRAME_STYLE,BORDER_SIZE,FRAME_COLOR)
     
     RETURN 0
END FUNCTION
FUNCTION gctrl_CLOAD          (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     STATIC    AS UI32        CLOAD
     DIM       AS TXT         TMPSTR
     DIM       AS I32         X,Y
     
     'COLOR AND TEXT UPDATE
     CLOAD = C_FPS
     '¤¤¤#277: "Control interface loop speed is "
     TMPSTR = LNG_SET_EXT(277,"Control interface loop speed is ")
     TMPSTR &= STR(CLOAD) & " Hz."
     MUTEXLOCK   MT_CTRL_INFO
     Controls[ID]->CTRL_INFO = TMPSTR
     MUTEXUNLOCK MT_CTRL_INFO
     
     IF     CLOAD < 420  THEN
          BACKGROUND = SWATCH0.BUTTON_BG_REC
     ELSEIF CLOAD < 880  THEN
          BACKGROUND = SWATCH0.BUTTON_BG_ACTIVE
     ELSEIF CLOAD < 1260 THEN
          BACKGROUND = SWATCH0.BUTTON_BG_ON
     ELSE
          BACKGROUND = SWATCH0.TAB_BG_ON
     END IF
     
     'BG + TEXT
     PATCH_BG()
     X = GDATA.X + BORDER_SIZE
     Y = GDATA.Y + BORDER_SIZE
     IF CONTROLS[ID]->NB_IMAGES > 0 ANDALSO CONTROLS[ID]->IMAGE[0] > 0 THEN _
        PUT DRAWING_DEST, (X,Y), Controls[ID]->IMAGE[0],ADD

     STYLE_FLAT_FRAME(SWATCH0.FRM_OFF)
     DrawFrame(GDATA,FRAME_STYLE,BORDER_SIZE,FRAME_COLOR)
     
     RETURN 0
END FUNCTION

FUNCTION gctrl_mic_power      (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM    AS I32  FS,X,Y
     STYLE_REC_POWER()
     PATCH_BG()
     IF CONTROLS[ID]->NB_IMAGES THEN
          X = GDATA.X + BORDER_SIZE
          Y = GDATA.Y + BORDER_SIZE
          ACETATE_TRANSFER(Controls[ID]->IMAGE[0],X,Y)
     END IF
     DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, FRAME_COLOR)
     RETURN 0
END FUNCTION
FUNCTION gctrl_mic_meter      (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM       AS I32         HalfH, HalfW, PowerW, FF, PMIN, PMAX, X,Y
     DIM       AS F32         PLevel
     STATIC    AS IOS         W,H
     STATIC    AS AD_POWER    PP(2)

     MUTEXLOCK   MT_AUDIO
     PP(0) = CP_PP(0)
     PP(1) = CP_PP(1)
     MUTEXUNLOCK MT_AUDIO

     STYLE_FLAT_FRAME(SWATCH0.FRM_OFF)
     BACKGROUND = SWATCH0.BUTTON_BG
     PATCH_BG()
     
     HalfW  = .5*GDATA.W
     HalfH  = .5*GDATA.H
     X = GDATA.X + HalfW
     Y = GDATA.Y
     W = GDATA.W
     H = GDATA.H
     
     'LEFT
     PLevel = (-dBmin32 + PP(0).POWER) / -dBmin32 '[0..1]
     PowerW = PLevel * .5*(W - BORDER_SIZE*2)
     PMIN  = HalfH*PP(0).MM(0)
     PMAX  = HalfH*PP(0).MM(1)
     LINE DRAWING_DEST,(X,Y+BORDER_SIZE)-(X-PowerW,Y+H-BORDER_SIZE-1),SWATCH0.BUTTON_BG_REC,BF 
     LINE DRAWING_DEST,(X,Y+HalfH-PMIN)-(X-PowerW,Y+HalfH-PMAX),ORANGE,BF
     
     'RIGHT
     PLevel = (-dBmin32 + PP(1).POWER) / -dBmin32 '[0..1]
     PowerW = PLevel * .5*(W - BORDER_SIZE*2)
     PMIN  = HalfH*PP(1).MM(0)
     PMAX  = HalfH*PP(1).MM(1)
     LINE DRAWING_DEST,(X,Y+BORDER_SIZE)-(X+PowerW,Y+H-BORDER_SIZE-1),SWATCH0.BUTTON_BG_REC,BF 
     LINE DRAWING_DEST,(X,Y+HalfH-PMIN)-(X+PowerW,Y+HalfH-PMAX),ORANGE,BF
     
     'SEPARATOR
     LINE DRAWING_DEST,(X,Y+BORDER_SIZE)-(X,Y+H-BORDER_SIZE-1),0
     
     'VOLUME
     PowerW = GDATA.X + BORDER_SIZE + .5*VOLUME_IN * (W-BORDER_SIZE-BORDER_SIZE-1)
     LINE DRAWING_DEST, (PowerW,Y+BORDER_SIZE)-(PowerW+1,Y+H-BORDER_SIZE),SWATCH0.BUTTON_BG_ACTIVE,BF
     IF GDATA.text.UPDATED THEN
          GDATA.TEXT.TEXT_WIDTH = GetTXT_W(GDATA.TEXT.CONTENT,MainFont,GDATA.TEXT.FONT_SIZE)
          IMAGEINFO(Controls[ID]->IMAGE[0],W,H)
          CEIL(GDATA.TEXT.TEXT_WIDTH,W)
          Controls[ID]->text.text_width = GDATA.TEXT.TEXT_WIDTH '!!!
          X      = .5*(W - GDATA.TEXT.TEXT_WIDTH)
          Y      = .5*(H - GDATA.text.font_size) + 1
          'PATCH BG AND PRINT TEXT
          LINE Controls[ID]->IMAGE[0],(0,0)-(W-1,H-1),0,BF
          PrintFT(Controls[ID]->IMAGE[0],X,Y,0,GDATA.TEXT.CONTENT,MainFont.Font_hdl,_
                  GDATA.TEXT.FONT_SIZE,GDATA.TEXT.FONT_CLR)
     END IF
     ACETATE_TRANSFER(Controls[ID]->IMAGE[0],GDATA.X+BORDER_SIZE,GDATA.Y+BORDER_SIZE)
     DrawFrame(GDATA,FRAME_STYLE,BORDER_SIZE,FRAME_COLOR)
     RETURN 0
END FUNCTION
FUNCTION gctrl_play_power     (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM    AS I32  FS,X,Y
     STYLE_PLAY_POWER()
     PATCH_BG()
     IF CONTROLS[ID]->NB_IMAGES THEN
          X = GDATA.X + BORDER_SIZE
          Y = GDATA.Y + BORDER_SIZE
          ACETATE_TRANSFER(Controls[ID]->IMAGE[0],X,Y)
     END IF
     DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, FRAME_COLOR)
     RETURN 0
END FUNCTION
FUNCTION gctrl_play_meter     (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM       AS I32         HalfH, HalfW, PowerW, FF, PMIN, PMAX, X,Y
     DIM       AS F32         PLevel
     STATIC    AS AD_POWER    PP(2)
     STATIC    AS IOS         W,H
     MUTEXLOCK   MT_AUDIO
     PP(0) = PB_PP(0)
     PP(1) = PB_PP(1)
     MUTEXUNLOCK MT_AUDIO

     STYLE_FLAT_FRAME(SWATCH0.FRM_OFF)
     BACKGROUND = SWATCH0.BUTTON_BG
     PATCH_BG()
     HalfW  = .5*GDATA.W
     HalfH  = .5*GDATA.H
     X = GDATA.X + HalfW
     Y = GDATA.Y
     W = GDATA.W
     H = GDATA.H
     
     'LEFT
     PLevel = (-dBmin32 + PP(0).POWER) / -dBmin32 '[0..1]
     PowerW = PLevel * .5*(W - BORDER_SIZE*2)
     PMIN  = HalfH*PP(0).MM(0)
     PMAX  = HalfH*PP(0).MM(1)
     LINE DRAWING_DEST,(X,Y+BORDER_SIZE)-(X-PowerW,Y+H-BORDER_SIZE-1),SWATCH0.BUTTON_BG_ON,BF 
     LINE DRAWING_DEST,(X,Y+HalfH-PMIN)-(X-PowerW,Y+HalfH-PMAX),SWATCH0.BUTTON_BG_ACTIVE,BF
     
     'RIGHT
     PLevel = (-dBmin32 + PP(1).POWER) / -dBmin32 '[0..1]
     PowerW = PLevel * .5*(W - BORDER_SIZE*2)
     PMIN  = HalfH*PP(1).MM(0)
     PMAX  = HalfH*PP(1).MM(1)
     LINE DRAWING_DEST,(X,Y+BORDER_SIZE)-(X+PowerW,Y+H-BORDER_SIZE-1),SWATCH0.BUTTON_BG_ON,BF 
     LINE DRAWING_DEST,(X,Y+HalfH-PMIN)-(X+PowerW,Y+HalfH-PMAX),SWATCH0.BUTTON_BG_ACTIVE,BF
     
     'SEPARATOR
     LINE DRAWING_DEST,(X,Y+BORDER_SIZE)-(X,Y+H-BORDER_SIZE-1),0
     
     'VOLUME
     PowerW = GDATA.X + BORDER_SIZE + VOLUME_OUT * (W-BORDER_SIZE-BORDER_SIZE-1)
     LINE DRAWING_DEST, (PowerW,Y+BORDER_SIZE)-(PowerW+1,Y+H-BORDER_SIZE),SWATCH0.BUTTON_BG_REC,BF
     IF GDATA.text.UPDATED THEN
          GDATA.TEXT.TEXT_WIDTH = GetTXT_W(GDATA.TEXT.CONTENT,MainFont,GDATA.TEXT.FONT_SIZE)
          IMAGEINFO(Controls[ID]->IMAGE[0],W,H)
          CEIL(GDATA.TEXT.TEXT_WIDTH,W)
          Controls[ID]->text.text_width = GDATA.TEXT.TEXT_WIDTH '!!!
          X      = .5*(W - GDATA.TEXT.TEXT_WIDTH)
          Y      = .5*(H - GDATA.text.font_size) + 1
          'PATCH BG AND PRINT TEXT
          LINE Controls[ID]->IMAGE[0],(0,0)-(W-1,H-1),0,BF
          PrintFT(Controls[ID]->IMAGE[0],X,Y,0,GDATA.TEXT.CONTENT,MainFont.Font_hdl,_
                  GDATA.TEXT.FONT_SIZE,GDATA.TEXT.FONT_CLR)
     END IF
     ACETATE_TRANSFER(Controls[ID]->IMAGE[0],GDATA.X+BORDER_SIZE,GDATA.Y+BORDER_SIZE)
     DrawFrame(GDATA,FRAME_STYLE,BORDER_SIZE,FRAME_COLOR)
     RETURN 0
END FUNCTION

FUNCTION gctrl_ctrl_info      (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM       AS I32         char_pos, X,Y,R, FONT_SIZE
     BACKGROUND = SWATCH0.TEXTAREA_BG
     PATCH_BG()
     STYLE_FLAT_FRAME(SWATCH0.FRM_OFF)
     FONT_SIZE  = GDATA.TEXT.FONT_SIZE
     'TEXT MANAGEMENT (FIXED IMAGE SIZE)
     IF Controls[ID]->NB_IMAGES > 0 ANDALSO Controls[ID]->IMAGE[0] > 0 THEN
          'REPRINT?
          MUTEXLOCK   MT_CTRL_INFO
          IF CONTROL_INFO.updated THEN
               DIM AS IOS W,H
               IF TRIM(CONTROL_INFO.content) = "" THEN CONTROL_INFO.content = DATE & "   " & TIME
               GDATA.TEXT.TEXT_WIDTH = GetTXT_W(CONTROL_INFO.content,MainFont,FONT_SIZE)
               IMAGEINFO(Controls[ID]->IMAGE[0],W,H)
               CEIL(GDATA.TEXT.TEXT_WIDTH,W)
               Controls[ID]->TEXT.TEXT_WIDTH = GDATA.TEXT.TEXT_WIDTH '!!!
               'CENTER
               X = .5*(W - GDATA.TEXT.TEXT_WIDTH)
               Y = .5*(H - GDATA.text.font_size) + 1
               'PATCH BG + REPRINT
               LINE Controls[ID]->IMAGE[0],(0,0)-(W-1,H-1),0,BF
               R = PrintFT(CONTROLS[ID]->IMAGE[0],X,Y,0,CONTROL_INFO.content,MainFont.Font_hdl,_
                   FONT_SIZE,SWATCH0.TEXTAREA_FG)
               CONTROL_INFO.updated = FALSE
          END IF
          MUTEXUNLOCK MT_CTRL_INFO
          ACETATE_TRANSFER(Controls[ID]->IMAGE[0],GDATA.X+BORDER_SIZE,GDATA.Y+BORDER_SIZE)
     END IF
     DrawFrame(GDATA,FRAME_STYLE,BORDER_SIZE,FRAME_COLOR)
     RETURN R
END FUNCTION

FUNCTION gctrl_msg_bar        (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     BACKGROUND = SWATCH0.TEXTAREA_BG
     PATCH_BG()
     IF GDATA.TEXT.UPDATED THEN
          DIM AS TXT TMPSTR
          DIM AS IOS X,Y,W,H
          GDATA.TEXT.TEXT_WIDTH = GetTXT_W(GDATA.TEXT.CONTENT,MainFont,GDATA.TEXT.FONT_SIZE)
          TMPSTR                = GDATA.TEXT.CONTENT
          'CONTENT ALIGNMENT
          IMAGEINFO(Controls[ID]->IMAGE[0],W,H)
          CEIL(GDATA.TEXT.TEXT_WIDTH,W)
          Controls[ID]->text.text_width = GDATA.TEXT.TEXT_WIDTH '!!!
          X  = 0
          Y  = .5*(H - GDATA.text.font_size) + 1
          X += .5*(W - GDATA.TEXT.TEXT_WIDTH)
          'BACKGROUND + PRINT
          LINE CONTROLS[ID]->IMAGE[0],(0,0)-(W-1,H-1),0,BF
          PrintFT(CONTROLS[ID]->IMAGE[0],X,Y,0,TMPSTR,MainFont.Font_hdl,_
                  GDATA.TEXT.FONT_SIZE,GDATA.TEXT.FONT_CLR,GLYPH_ALPHA)
     END IF
     ACETATE_TRANSFER(Controls[ID]->IMAGE[0],GDATA.X+BORDER_SIZE,GDATA.Y+BORDER_SIZE)
     DrawFrame(GDATA,FR_SOLID,BORDER_SIZE,SWATCH0.FRM_ON)
     RETURN 0
END FUNCTION

FUNCTION gctrl_dialog_text    (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM       AS I32         X,Y
     
     BACKGROUND = SWATCH0.TEXTAREA_BG
     PATCH_BG()
     STYLE_FLAT_FRAME(SWATCH0.FRM_OFF)
     
     'TEXT MANAGEMENT (FIXED IMAGE SIZE)
     IF Controls[ID]->NB_IMAGES > 0 ANDALSO Controls[ID]->IMAGE[0] > 0 THEN
          'REPRINT?
          IF GDATA.text.updated THEN
               DIM AS IOS W,H
               GDATA.TEXT.TEXT_WIDTH = GetTXT_W(GDATA.text.content,MainFont,GDATA.text.FONT_SIZE)
               IMAGEINFO(Controls[ID]->IMAGE[0],W,H)
               CEIL(GDATA.TEXT.TEXT_WIDTH,W)
               Controls[ID]->text.text_width = GDATA.TEXT.TEXT_WIDTH '!!!
               Y = .5*(H - GDATA.text.font_size) + 1
               X = 0
               'PATCH BG + REPRINT
               LINE Controls[ID]->IMAGE[0],(0,0)-(W-1,H-1),0,BF
               gctrl_err = PrintFT(CONTROLS[ID]->IMAGE[0],X,Y,BORDER_SIZE+1,GDATA.text.content,_
                           MainFont.Font_hdl,GDATA.TEXT.FONT_SIZE,SWATCH0.TEXTAREA_FG,GLYPH_ALPHA)
               IF gctrl_err < 0 THEN RETURN gctrl_err
          END IF
          ACETATE_TRANSFER(Controls[ID]->IMAGE[0],GDATA.X+BORDER_SIZE,GDATA.Y+BORDER_SIZE)
     END IF
     
     DrawFrame(GDATA,FRAME_STYLE,BORDER_SIZE,FRAME_COLOR)
     RETURN 0
END FUNCTION
FUNCTION gctrl_text_field     (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM       AS I32              X,Y, hx, l, r, w2, h2, TEXT_WIDTH=1, HM, TM, TEXT_SIZE
     DIM       AS I32              CPX,VPX0,VPX1,SPX0,SPW
     DIM       AS STRING           CONTENT, TEXT_VIEW
     DIM       AS _SUPER_TEXT      PTR T

     STYLE_FIELD_FRAME()

     'SHORTCUTS
     T          = @GDATA.TEXT
     BACKGROUND = SWATCH0.WINDOW_BG
     FOREGROUND = WHITE
     TEXT_SIZE  = T->FONT_SIZE
     CONTENT    = T->content

     'SIZE
     HM         = BORDER_SIZE + .5*TEXT_SIZE           'HORIZONTAL MARGIN  (PX)
     W2         = GDATA.w - 2*HM                       'FIELD MARGIN       (PX)
     TM         = .5*(GDATA.H - TEXT_SIZE)             'TOP MARGIN         (PX)

     'RECALC CURSOR AND AND VIEW RANGE (PIXELS)
     CPX  = GetTXT_W(MID(CONTENT,T->VP0+1,T->CP - T->VP0),MainFont, TEXT_SIZE) - 1
     FLOOR(CPX,0)
     VPX0 = GetTXT_W(MID(CONTENT,1,T->VP0),MainFont, TEXT_SIZE) - 1
     FLOOR(VPX0,0)
     VPX1 = GetTXT_W(MID(CONTENT,T->VP0+1,T->VP1 - T->VP0),MainFont, TEXT_SIZE) - 1
     CEIL(VPX1,W2)

     'SELECTION
     
     IF T->SL THEN
          IF T->SP < T->VP0 THEN 
               SPX0 = 0
               SPW  = CPX+1
          ELSEIF T->SP >= T->VP1 THEN
               SPX0 = CPX
               SPW  = VPX1 - CPX
          ELSE
               SPX0 = GetTXT_W(MID(CONTENT,T->VP0+1,T->SP - T->VP0),MainFont, TEXT_SIZE) - 1
               SPW  = CPX - SPX0
               IF SPW < 0 THEN
                    SPW  = -SPW
                    SPX0 = CPX
               END IF
          END IF
     END IF
     VPX1 += VPX0

     'TEXT UPDATE
     IF T->UPDATED THEN
          'REDRAW TEXT STRING IN VIEW RANGE
          TEXT_VIEW  = MID(CONTENT,T->VP0+1,T->VP1-T->VP0)
          TEXT_WIDTH = GetTXT_W(TEXT_VIEW, MainFont, TEXT_SIZE) + 1
          LINE Controls[ID]->IMAGE[0],(0,0)-(GDATA.W-3,TEXT_SIZE+2),0,BF
          R = PrintFT(Controls[ID]->IMAGE[0],0,0,0,TEXT_VIEW,MainFont.Font_hdl,TEXT_SIZE,FOREGROUND,_
              GLYPH_ALPHA)
          IF R < 0 THEN RETURN R
     END IF

     'DRAWINGS
          'BACKGROUND
     PATCH_BG()
          'SELECTION HIGHLIGHT
     IF T->SL THEN LINE DRAWING_DEST,(GDATA.X+HM+SPX0,GDATA.Y+BORDER_SIZE)-(GDATA.X+HM+SPX0+SPW-1,_
                                      GDATA.Y+GDATA.H-BORDER_SIZE-1),SWATCH0.TEXTAREA_BG_HL,BF
          'PUT TEXT IMAGE TO LAYER
     PUT  DRAWING_DEST, (GDATA.X+HM,GDATA.Y+TM),Controls[ID]->IMAGE[0], ALPHA
          'CURSOR [  |   ]
     LINE DRAWING_DEST, (GDATA.X+HM+CPX,GDATA.Y+BORDER_SIZE)-(GDATA.X+HM+CPX,_
                         GDATA.Y+GDATA.H-BORDER_SIZE-1), WHITE
          'EXTENSION DOTS ::: L/R, MEANING THERE'S TEXT OUTSIDE THE CURRENT VIEW RANGE
     IF T->VP0 > 0 THEN LINE DRAWING_DEST,(GDATA.X+BORDER_SIZE,GDATA.Y+BORDER_SIZE)-_
  (GDATA.X+BORDER_SIZE+1,GDATA.Y+GDATA.H-BORDER_SIZE-1),SWATCH0.BUTTON_BG_ACTIVE,B,&b1100110011001100
     IF T->VP1 < T->LS-1 THEN LINE DRAWING_DEST,(GDATA.X+GDATA.W-BORDER_SIZE-1,GDATA.Y+BORDER_SIZE)-_
  (GDATA.X+GDATA.W-BORDER_SIZE-2,GDATA.Y+GDATA.H-BORDER_SIZE-1),SWATCH0.BUTTON_BG_ACTIVE,B,&b1100110011001100

     DrawFrame(GDATA,FRAME_STYLE,BORDER_SIZE,FRAME_COLOR)
     RETURN 0
END FUNCTION

'------------------------------------------------------------------------------------------------------------
' TOOLS

FUNCTION gctrl_module_infos   (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM    AS I32 X,Y
     X = GDATA.X + BORDER_SIZE + GRID_STEP
     Y = GDATA.Y + BORDER_SIZE + GRID_STEP
     PUT DRAWING_DEST, (X, Y), Controls[ID]->IMAGE[0], ADD
     Y += GRID_STEP * 14
     PUT DRAWING_DEST, (X, Y), Controls[ID]->IMAGE[1], ADD
     DrawFrame(GDATA,FR_SOLID, BORDER_SIZE, SWATCH0.FRM_OFF)
     RETURN 0
END FUNCTION

FUNCTION gctrl_shape_graph   (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     STATIC AS I32  SID, W2,H2, I, HalfH, A
     STATIC AS F32  F,T

     IF GDATA.TEXT.UPDATED THEN
          W2 = GDATA.W - BORDER_SIZE * 2
          H2 = GDATA.H - BORDER_SIZE * 2
          LINE Controls[ID]->IMAGE[0], (0,0)-(W2-1,H2-1),GDATA.CLR,BF
          SID = GDATA.TEXT.si
          IF SID > -1 THEN
               F = 1 / W2
               HalfH = .5*H2
               FOR I = 0 TO W2 - 1
                    T = I / W2
                    A = (HalfH-1) * SOUNDRA.GENERATOR(SID)(T,1,F,0,1,1)
                    LINE Controls[ID]->IMAGE[0],(I,HalfH-A)-(I,HalfH),WHITE
               NEXT I
          END IF
     END IF
     PUT DRAWING_DEST,(GDATA.X+BORDER_SIZE,GDATA.Y+BORDER_SIZE),Controls[ID]->IMAGE[0], PSET
     DrawFrame(GDATA,FR_SOLID, BORDER_SIZE, SWATCH0.BUTTON_BG)
     RETURN 0
END FUNCTION

FUNCTION gctrl_filter_graph   (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     STATIC AS I32  W2,H2,Wx, I,T, HalfH, A
     STATIC AS F32  Tx
     IF GDATA.TEXT.UPDATED THEN
          'BACKGROUND RESET
          W2 = GDATA.W - BORDER_SIZE * 2
          H2 = GDATA.H - BORDER_SIZE * 2
          LINE Controls[ID]->IMAGE[0], (0,0)-(W2-1,H2-1),GDATA.CLR,BF
          'BAR WIDTH
          Wx = W2 / SOUNDRA.FD.N
          FLOOR(Wx,1)
          'DRAW SIGNAL
          HalfH = .5*H2
          Tx = W2 / SOUNDRA.FD.N
          FOR I = 0 TO SOUNDRA.FD.N-1
               T = INT(Tx * I) + BORDER_SIZE
               A = (HalfH-1) * SOUNDRA.FD.COEFF[I]
               LINE Controls[ID]->IMAGE[0],(T,HalfH-A)-(T+Wx,HalfH),WHITE,BF
               A = (HalfH-1) * SOUNDRA.FD.WIN[I]
               LINE Controls[ID]->IMAGE[0],(T,HalfH-A)-(T+Wx,HalfH-A),PINK
          NEXT I
          'AXIS
          T = BORDER_SIZE + Tx * SOUNDRA.FD.N\2
          LINE Controls[ID]->IMAGE[0],(BORDER_SIZE,HalfH)-(BORDER_SIZE+W2-1,HalfH),PINK
          LINE Controls[ID]->IMAGE[0],(T,BORDER_SIZE)-(T,BORDER_SIZE+H2-1),PINK
     END IF
     PUT DRAWING_DEST,(GDATA.X+BORDER_SIZE,GDATA.Y+BORDER_SIZE),Controls[ID]->IMAGE[0], PSET
     DrawFrame(GDATA,FR_SOLID, BORDER_SIZE, SWATCH0.BUTTON_BG)
     RETURN 0
END FUNCTION

'------------------------------------------------------------------------------------------------------------
' BROWSER AND LISTS

FUNCTION gctrl_list_sort      (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM    AS I32 X,Y, I
     STYLE_BUTTON()
     PATCH_BG()
     Y = GDATA.Y + BORDER_SIZE + .5*(GDATA.H - GDATA.text.font_size)
     X = GDATA.X + .5*(GDATA.W - GDATA.TEXT.TEXT_WIDTH) + 1
     I = Controls[ID]->INDEX
     PUT DRAWING_DEST, (X, Y), Controls[ID]->IMAGE[I], ADD
     DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, FRAME_COLOR)
     RETURN 0
END FUNCTION

FUNCTION gctrl_file_drives    (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM    AS I32  I,X,Y,X2,Y2,W2
     DIM AS TXT     TMPSTR

     FOREGROUND = SWATCH0.TAB_FG
     STYLE_FLAT_FRAME(SWATCH0.FRM_OFF)

     X  = GDATA.X + BORDER_SIZE
     Y  = GDATA.Y + BORDER_SIZE
     W2 = (GDATA.W - BORDER_SIZE * 2) / DRIVES.NB_DRIVES

     'TEXT UPDATE
     IF GDATA.TEXT.UPDATED THEN
          IF (Controls[ID]->NB_IMAGES > 0) ANDALSO (Controls[ID]->IMAGE[0] > 0) THEN
               LINE Controls[ID]->IMAGE[0],(0,0)-(GDATA.W-1,GDATA.H-1),0,BF
               FOR I = 1 TO DRIVES.NB_DRIVES
                    X2 = (I-1) * W2 + .5*(W2 - GetTXT_W("W:\",MainFont, GDATA.TEXT.FONT_SIZE))
                    TMPSTR = DRIVES.DriveLetters(I) & ":\"
                    PrintFT(Controls[ID]->IMAGE[0],X2,0,0,TMPSTR,MainFont.Font_hdl,_
                            GDATA.TEXT.FONT_SIZE,FOREGROUND,GLYPH_ADD)
               NEXT I
          END IF
     END IF
     'BACKGROUND
     FOR I = 1 TO DRIVES.NB_DRIVES
          IF I = GDATA.TEXT.hi THEN
               BACKGROUND = SWATCH0.BUTTON_BG_ACTIVE
          ELSEIF I = GDATA.TEXT.si THEN
               BACKGROUND = SWATCH0.TAB_BG_ON
          ELSE
               BACKGROUND = SWATCH0.TAB_BG
          END IF               
          LINE DRAWING_DEST, (X,Y)-(X+W2-1,Y+GDATA.H-1), BACKGROUND, BF
          X += W2
     NEXT I
     'TEXT
     X = GDATA.X + BORDER_SIZE
     Y = GDATA.Y + .5*(GDATA.H - GDATA.TEXT.FONT_SIZE) + 1
     IF (Controls[ID]->NB_IMAGES > 0) ANDALSO (Controls[ID]->IMAGE[0] > 0) THEN _
        PUT DRAWING_DEST,(X,Y),Controls[ID]->IMAGE[0],ADD

     DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, FRAME_COLOR)
     RETURN 0
END FUNCTION
     
FUNCTION gctrl_system_list    (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     GLIST_VARIABLES()

     MUTEXLOCK   LI_ConsoleMSG.MUTEX
     list_size = LI_ConsoleMSG.LENGTH
     MUTEXUNLOCK LI_ConsoleMSG.MUTEX
     
     GLIST_TOP_CODE(0)

     'DRAWING LOOP
     FOR I = start TO finish STEP S
          'BACKGROUND
          BACKGROUND = alt_line_clr(I,SWATCH0.LIST_BG)
          FOREGROUND = SWATCH0.LIST_FG
          IF I = GDATA.TEXT.si     THEN           'SELECTED
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          END IF
          IF I = GDATA.TEXT.hi THEN               'HOVER
               IF I <> GDATA.TEXT.si THEN
                    BACKGROUND = SWATCH0.LIST_BG_HL
                    FOREGROUND = SWATCH0.LIST_FG_HL
               END IF
               TMPSTR = GetConsoleMsg(I)         'FUNCTION USES A MUTEX
               MUTEXLOCK   MT_CTRL_INFO
               Controls[ID]->CTRL_INFO = TMPSTR
               MUTEXUNLOCK MT_CTRL_INFO
          END IF
          LINE DRAWING_DEST, (X,Y)-(X+GDATA.W-BORDER_SIZE-1,Y+LINE_H-1),BACKGROUND,BF

          'TEXT IMAGE
          IF GDATA.TEXT.UPDATED THEN
               TMPSTR = GetConsoleMsg(I)
               IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN
                    LINE Controls[ID]->IMAGE[B],(0,0)-(W-1,GDATA.TEXT.FONT_SIZE),0,BF
                    PrintFT(Controls[ID]->IMAGE[B],GRID_STEP,0,0,TMPSTR, _
                              MainFont.Font_hdl,GDATA.TEXT.FONT_SIZE,FOREGROUND)
               END IF
          END IF
          'DRAW TEXT IMAGE
          IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN _
               PUT DRAWING_DEST,(X,Y + Y0), Controls[ID]->IMAGE[B], ALPHA
          Y += LINE_H
          B += 1
     NEXT I
     
     GLIST_BOTTOM_CODE()
     RETURN 0
END FUNCTION

FUNCTION gctrl_action_list    (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     GLIST_VARIABLES()

     MUTEXLOCK   LI_LOG_ACTIONS.MUTEX
     list_size = LI_LOG_ACTIONS.LENGTH
     MUTEXUNLOCK LI_LOG_ACTIONS.MUTEX
     
     GLIST_TOP_CODE(0)

     'DRAWING LOOP
     FOR I = start TO finish STEP S
          'BACKGROUND
          BACKGROUND = alt_line_clr(I,SWATCH0.LIST_BG)
          FOREGROUND = SWATCH0.LIST_FG
          IF I = GDATA.TEXT.si     THEN           'SELECTED (PRIORITY OVER HOVER)
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          END IF
          IF I = GDATA.TEXT.hi THEN               'HOVER
               IF I <> GDATA.TEXT.si THEN
                    BACKGROUND = SWATCH0.LIST_BG_HL
                    FOREGROUND = SWATCH0.LIST_FG_HL
               END IF
               TMPSTR = ""
               MUTEXLOCK   LI_LOG_ACTIONS.MUTEX
               IF (I < LI_LOG_ACTIONS.LENGTH) THEN TMPSTR = *LOG_ACTIONS[I]
               MUTEXUNLOCK LI_LOG_ACTIONS.MUTEX
               MUTEXLOCK   MT_CTRL_INFO
               Controls[ID]->CTRL_INFO = TMPSTR
               MUTEXUNLOCK MT_CTRL_INFO
          END IF
          LINE DRAWING_DEST, (X,Y)-(X+GDATA.W-BORDER_SIZE-1,Y+LINE_H-1),BACKGROUND,BF

          'TEXT IMAGE, IF ANY
          IF GDATA.TEXT.UPDATED THEN
               TMPSTR = ""
               MUTEXLOCK   LI_LOG_ACTIONS.MUTEX
               IF (I < LI_LOG_ACTIONS.LENGTH) THEN TMPSTR = *LOG_ACTIONS[I]
               MUTEXUNLOCK LI_LOG_ACTIONS.MUTEX
               IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN
                    LINE Controls[ID]->IMAGE[B],(0,0)-(W-1,GDATA.TEXT.FONT_SIZE),0,BF
                    PrintFT(Controls[ID]->IMAGE[B],GRID_STEP,0,0,TMPSTR, _
                              MainFont.Font_hdl,GDATA.TEXT.FONT_SIZE,FOREGROUND)
               END IF
          END IF
          'DRAW TEXT IMAGE
          IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN _
               PUT DRAWING_DEST,(X,Y + Y0), Controls[ID]->IMAGE[B], ALPHA
          Y += LINE_H
          B += 1
     NEXT I
     
     GLIST_BOTTOM_CODE()
     RETURN 0
END FUNCTION

FUNCTION gctrl_file_list      (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     GLIST_VARIABLES()
     DIM AS IOS     IS_FOLDER

     MUTEXLOCK   FOLDER0.LI_ITEM.MUTEX
     list_size = FOLDER0.LI_ITEM.LENGTH
     MUTEXUNLOCK FOLDER0.LI_ITEM.MUTEX
     
     GLIST_TOP_CODE(0)

     'DRAWING LOOP
     FOR I = start TO finish STEP S
          'BACKGROUND
          BACKGROUND = alt_line_clr(I,SWATCH0.LIST_BG)
          FOREGROUND = SWATCH0.LIST_FG
          IF I = GDATA.TEXT.si     THEN           'SELECTED (PRIORITY OVER HOVER)
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          END IF
          IF I = GDATA.TEXT.hi THEN           'HOVER
               IF I <> GDATA.TEXT.si THEN
                    BACKGROUND = SWATCH0.LIST_BG_HL
                    FOREGROUND = SWATCH0.LIST_FG_HL
               END IF
               MUTEXLOCK   FOLDER0.LI_ITEM.MUTEX
               TMPSTR    = FOLDER0.GetName(I)
               IS_FOLDER = (FOLDER0.GetAttr(I) AND fbDirectory)
               MUTEXUNLOCK FOLDER0.LI_ITEM.MUTEX
               MUTEXLOCK   MT_CTRL_INFO
               Controls[ID]->CTRL_INFO = TMPSTR
               MUTEXUNLOCK MT_CTRL_INFO
          END IF
          LINE DRAWING_DEST, (X,Y)-(X+GDATA.W-BORDER_SIZE-1,Y+LINE_H-1),BACKGROUND,BF

          'TEXT IMAGE, IF ANY
          IF GDATA.TEXT.UPDATED THEN
               MUTEXLOCK   FOLDER0.LI_ITEM.MUTEX
               TMPSTR    = FOLDER0.GetName(I)
               IS_FOLDER = (FOLDER0.GetAttr(I) AND fbDirectory)
               MUTEXUNLOCK FOLDER0.LI_ITEM.MUTEX
               IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN
                    LINE Controls[ID]->IMAGE[B],(0,0)-(W-1,GDATA.TEXT.FONT_SIZE),0,BF
                    IF IS_FOLDER THEN _
                       PrintFT(Controls[ID]->IMAGE[B],GRID_STEP,2,0,CHR(&h46),IconFont,ICON_SIZE,FOREGROUND)
                    PrintFT(Controls[ID]->IMAGE[B],ICON_SIZE+GRID_STEP+GRID_STEP,1,0,TMPSTR, _
                            MainFont.Font_hdl,GDATA.TEXT.FONT_SIZE,FOREGROUND)
               END IF
          END IF
          'DRAW TEXT IMAGE
          IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN _
               PUT DRAWING_DEST,(X,Y + Y0), Controls[ID]->IMAGE[B], ALPHA
          Y += LINE_H
          B += 1
     NEXT I

     GLIST_BOTTOM_CODE()
     RETURN 0
END FUNCTION

FUNCTION gctrl_reference_list       (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     GLIST_VARIABLES()
     STATIC AS I32  CAT_CLR
     
     list_size = SOUNDRA.CATALOG_SIZE
     
     GLIST_TOP_CODE(1)

     'DRAWING LOOP
     FOR I  = start TO finish STEP S
          'BACKGROUND
          BACKGROUND = alt_line_clr(I,SWATCH0.LIST_BG)
          FOREGROUND = SWATCH0.LIST_FG
          CAT_CLR = BACKGROUND
          IF I = GDATA.TEXT.si THEN           'SELECTED (PRIORITY OVER HOVER)
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          END IF
          IF I = GDATA.TEXT.hi THEN           'HOVER
               IF I <> GDATA.TEXT.si THEN
                    BACKGROUND = SWATCH0.LIST_BG_HL
                    FOREGROUND = SWATCH0.LIST_FG_HL
               END IF
               TMPSTR = SOUNDRA.REFERENCE_MODULE(SOUNDRA.MM_MAP(I)).Label
               MUTEXLOCK   MT_CTRL_INFO
               Controls[ID]->CTRL_INFO = TMPSTR
               MUTEXUNLOCK MT_CTRL_INFO
          END IF
          CAT_CLR = SOUNDRA.MODULE_COLOR(SOUNDRA.REFERENCE_MODULE(SOUNDRA.MM_MAP(I)).CATEGORY)
          
          LINE DRAWING_DEST, (X,Y)-(X+GDATA.W-BORDER_SIZE-1,Y+LINE_H-1),BACKGROUND,BF
          LINE DRAWING_DEST, (X,Y)-(X+8,Y+LINE_H-1), GREY(20),B
          LINE DRAWING_DEST, (X+1,Y+1)-(X+7,Y+LINE_H-2), CAT_CLR,BF

          'TEXT IMAGE, IF ANY
          IF GDATA.TEXT.UPDATED THEN
               TMPSTR = SOUNDRA.REFERENCE_MODULE(SOUNDRA.MM_MAP(I)).Label
               IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN
                    LINE Controls[ID]->IMAGE[B],(0,0)-(W-1,GDATA.TEXT.FONT_SIZE),0,BF
                    PrintFT(Controls[ID]->IMAGE[B],3*GRID_STEP,0,0,TMPSTR, _
                              MainFont.Font_hdl,GDATA.TEXT.FONT_SIZE,FOREGROUND)
               END IF
          END IF
          'DRAW TEXT IMAGE
          IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN _
               PUT DRAWING_DEST,(X,Y + Y0), Controls[ID]->IMAGE[B], ALPHA
          'VOICE SUPPORT ICON
          IF (SOUNDRA.REFERENCE_MODULE(SOUNDRA.MM_MAP(I)).VOICE_SUPPORT > 0) THEN _
               PUT DRAWING_DEST,(X+W-ICON_SIZE-3,Y+Y0-1),Controls[ID]->IMAGE[0], ALPHA
          Y += LINE_H
          B += 1
     NEXT I
     
     GLIST_BOTTOM_CODE()
     RETURN 0
END FUNCTION

FUNCTION gctrl_library_list         (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     GLIST_VARIABLES()
     STATIC AS I32       CAT_CLR
     DIM AS _TEXTLINE    PTR LABELS
     DIM AS I32          PTR TYPE_IDS,CATS,ISPOLY

     MUTEXLOCK   SOUNDRA.LI_MODULES.MUTEX
     list_size = SOUNDRA.LI_MODULES.LENGTH
     MUTEXUNLOCK SOUNDRA.LI_MODULES.MUTEX
     
     GLIST_TOP_CODE(1)
     
     'MEMORY ALLOCATION
     LABELS    = NEW _TEXTLINE[list_size]
     TYPE_IDS  = NEW I32[list_size]
     CATS      = NEW I32[list_size]
     ISPOLY    = NEW I32[list_size]
     'COPY WHAT'S VISIBLE
     MUTEXLOCK   SOUNDRA.LI_MODULES.MUTEX
     FOR I = start TO finish STEP S
          IF SOUNDRA.MODULES[I] > 0 THEN
               LABELS[I]   = SOUNDRA.MODULES[I]->Label
               TYPE_IDS[I] = SOUNDRA.MODULES[I]->TYPE_ID
               CATS[I]     = SOUNDRA.MODULES[I]->CATEGORY
               ISPOLY[I]   = SOUNDRA.MODULES[I]->FLAGS(SOUNDRA.MF_VOICE_MODE)
          END IF
     NEXT I
     MUTEXUNLOCK SOUNDRA.LI_MODULES.MUTEX

     'DRAWING LOOP
     FOR I = start TO finish STEP S
          'BACKGROUND
          BACKGROUND = alt_line_clr(I,SWATCH0.LIST_BG)
          FOREGROUND = SWATCH0.LIST_FG
          CAT_CLR    = BACKGROUND
          IF I = GDATA.TEXT.si     THEN           'SELECTED (PRIORITY OVER HOVER)
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          END IF
          IF I = GDATA.TEXT.hi THEN               'HOVER
               IF I <> GDATA.TEXT.si THEN
                    BACKGROUND = SWATCH0.LIST_BG_HL
                    FOREGROUND = SWATCH0.LIST_FG_HL
               END IF
               TMPSTR = LABELS[I] & " #" & STR(TYPE_IDS[I])
               MUTEXLOCK   MT_CTRL_INFO
               Controls[ID]->CTRL_INFO = TMPSTR
               MUTEXUNLOCK MT_CTRL_INFO
          END IF
          CAT_CLR = SOUNDRA.MODULE_COLOR(CATS[I])
          
          LINE DRAWING_DEST, (X,Y)-(X+GDATA.W-BORDER_SIZE-1,Y+LINE_H-1),BACKGROUND,BF
          LINE DRAWING_DEST, (X,Y)-(X+8,Y+LINE_H-1), GREY(20),B
          LINE DRAWING_DEST, (X+1,Y+1)-(X+7,Y+LINE_H-2), CAT_CLR,BF
          
          'TEXT PRINTING
          IF GDATA.TEXT.UPDATED THEN
               TMPSTR = LABELS[I] & " #" & STR(TYPE_IDS[I])
               IF (B < Controls[ID]->NB_IMAGES) ANDALSO (Controls[ID]->IMAGE[B] > 0) THEN
                    LINE Controls[ID]->IMAGE[B],(0,0)-(W-1,GDATA.TEXT.FONT_SIZE),0,BF
                    PrintFT(Controls[ID]->IMAGE[B],3*GRID_STEP,0,0,TMPSTR, _
                              MainFont.Font_hdl,GDATA.TEXT.FONT_SIZE,FOREGROUND)
               END IF
          END IF
          'DRAW TEXT IMAGE
          IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN _
               PUT DRAWING_DEST,(X,Y + Y0), Controls[ID]->IMAGE[B], ALPHA
          'VOICE SUPPORT ICON
          IF ISPOLY[I] = TRUE THEN PUT DRAWING_DEST,(X+W-ICON_SIZE-5,Y+Y0),Controls[ID]->IMAGE[0], ALPHA
          Y += LINE_H
          B += 1
     NEXT I
     
     GLIST_BOTTOM_CODE()
     
     IF LABELS   THEN DELETE[] LABELS
     IF TYPE_IDS THEN DELETE[] TYPE_IDS
     IF CATS     THEN DELETE[] CATS
     IF ISPOLY   THEN DELETE[] ISPOLY

     RETURN 0
END FUNCTION

FUNCTION gctrl_sample_list         (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     GLIST_VARIABLES()
     DIM AS F32     D
     DIM AS TXT     FILENAME, CHANNELS, DURATION
     
     MUTEXLOCK   LI_WF_Library.MUTEX
     list_size = LI_WF_Library.LENGTH
     MUTEXUNLOCK LI_WF_Library.MUTEX

     GLIST_TOP_CODE(0)
     
     MUTEXLOCK   LI_WF_Library.MUTEX
     'DRAWING LOOP
     FOR I  = start TO finish STEP S
          'BACKGROUND
          BACKGROUND = alt_line_clr(I,SWATCH0.LIST_BG)
          FOREGROUND = SWATCH0.LIST_FG
          IF I = GDATA.TEXT.si     THEN           'SELECTED (PRIORITY OVER HOVER)
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          END IF
          IF I = GDATA.TEXT.hi THEN           'HOVER
               IF I <> GDATA.TEXT.si THEN
                    BACKGROUND = SWATCH0.LIST_BG_HL
                    FOREGROUND = SWATCH0.LIST_FG_HL
               END IF
               IF (I < LI_WF_Library.LENGTH) ANDALSO (WF_Library[I] > 0) THEN
                    CHANNELS = SCHAN_NAME(WF_Library[I]->WaveFile.WaveFormat.nbChannels)
                    FILENAME = WF_Library[I]->FileName
                    D        = WF_Library[I]->Duration
               END IF
               DURATION = S2TXT(D)
               TMPSTR = FILENAME & " (" & CHANNELS & ", " & DURATION & ")"
               MUTEXLOCK   MT_CTRL_INFO
               Controls[ID]->CTRL_INFO = TMPSTR
               MUTEXUNLOCK MT_CTRL_INFO
          END IF
          LINE DRAWING_DEST, (X,Y)-(X+GDATA.W-BORDER_SIZE-1,Y+LINE_H-1),BACKGROUND,BF

          'TEXT PRINTING
          IF GDATA.TEXT.UPDATED THEN
               TMPSTR = ""
               IF (WF_Library[I] > 0) THEN
                    CHANNELS = SCHAN_TAG(WF_Library[I]->WaveFile.WaveFormat.nbChannels) & " "
                    FILENAME = WF_Library[I]->FileName
                    D        = WF_Library[I]->Duration
               END IF
               DURATION = S2TXT(D)
               IF (B < Controls[ID]->NB_IMAGES) ANDALSO (Controls[ID]->IMAGE[B] > 0) THEN
                    DIM AS I32 F2 = GDATA.TEXT.FONT_SIZE-3
                    FLOOR(F2,MIN_FONT_SIZE)
                    LINE Controls[ID]->IMAGE[B],(0,0)-(W-1,GDATA.TEXT.FONT_SIZE),0,BF
                    PrintFT(Controls[ID]->IMAGE[B],GRID_STEP,GRID_STEP-1,0,CHANNELS, _
                              MainFont.Font_hdl,F2,FOREGROUND)
                    PrintFT(Controls[ID]->IMAGE[B],6*GRID_STEP,GRID_STEP-1,0,DURATION, _
                              MainFont.Font_hdl,F2,FOREGROUND)
                    PrintFT(Controls[ID]->IMAGE[B],20*GRID_STEP,0,0,FILENAME, _
                              MainFont.Font_hdl,GDATA.TEXT.FONT_SIZE,FOREGROUND)
               END IF
          END IF
          'DRAW TEXT IMAGE
          IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN _
               PUT DRAWING_DEST,(X,Y + Y0), Controls[ID]->IMAGE[B], ALPHA
          Y += LINE_H
          B += 1
     NEXT I
     MUTEXUNLOCK LI_WF_Library.MUTEX
     
     GLIST_BOTTOM_CODE()
     RETURN 0
END FUNCTION

FUNCTION gctrl_sample_list_m       (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     GLIST_VARIABLES()
     DIM AS I32               J,C
     DIM AS F32               D
     DIM AS TXT               FILENAME, DURATION
     DIM AS SOUNDRA.MODULE    PTR SEL_PTR
     DIM AS _WF_CATALOG       PTR WF_PTR
     DIM AS I32               PTR WF_STATUS, WF_ISNODATA
     DIM AS I16               PTR WF_CHANNELS
     DIM AS F32               PTR WF_DURATIONS
     DIM AS _TEXTLINE         PTR WF_NAMES
     DIM AS I32               WF_SEL_ID = -1
     
     'GET WAVE FILE POINTER
     MUTEXLOCK   SOUNDRA.LI_MODULES.MUTEX
     SEL_PTR = SOUNDRA.SELECTED_MODULE
     IF SEL_PTR > 0 THEN WF_PTR = SEL_PTR->WF_PTR
     MUTEXUNLOCK SOUNDRA.LI_MODULES.MUTEX
     
     MUTEXLOCK   LI_WF_Sample.MUTEX
     list_size = LI_WF_Sample.LENGTH
     MUTEXUNLOCK LI_WF_Sample.MUTEX
     
     GLIST_TOP_CODE(3)
     
     'MEMORY ALLOCATION
     WF_STATUS      = NEW I32[list_size]
     WF_CHANNELS    = NEW I16[list_size]
     WF_ISNODATA    = NEW I32[list_size]
     WF_DURATIONS   = NEW F32[list_size]
     WF_NAMES       = NEW _TEXTLINE[list_size]
     MUTEXLOCK   LI_WF_Sample.MUTEX
     'COPY WHAT'S VISIBLE
     FOR I = start TO finish STEP S
          IF WF_Sample[I] > 0 THEN
               IF (WF_PTR > 0) ANDALSO (WF_Sample[I] = WF_PTR) THEN WF_SEL_ID = I
               WF_ISNODATA[I]  = (WF_Sample[I]->WaveFile.AudioData = 0) 'I32
               WF_STATUS[I]    = WF_Sample[I]->STATUS 'I32
               WF_CHANNELS[I]  = WF_Sample[I]->WaveFile.WaveFormat.nbChannels 'I16
               WF_DURATIONS[I] = WF_Sample[I]->Duration 'F32
               WF_NAMES[I]     = WF_Sample[I]->FileName
          END IF
     NEXT I
     MUTEXUNLOCK LI_WF_Sample.MUTEX
     
     'DRAWING LOOP
     FOR I = start TO finish STEP S
          'BACKGROUND
          BACKGROUND = alt_line_clr(I,SWATCH0.LIST_BG)
          FOREGROUND = SWATCH0.LIST_FG
          IF I = GDATA.TEXT.si     THEN           'SELECTED (PRIORITY OVER HOVER)
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          END IF
          IF I = GDATA.TEXT.hi THEN               'HOVER
               IF I <> GDATA.TEXT.si THEN
                    BACKGROUND = SWATCH0.LIST_BG_HL
                    FOREGROUND = SWATCH0.LIST_FG_HL
               END IF
               TMPSTR = WF_NAMES[I] & " (" & SCHAN_NAME(WF_CHANNELS[I]) & ", " & S2TXT(WF_DURATIONS[I]) & ")"
               MUTEXLOCK   MT_CTRL_INFO
               Controls[ID]->CTRL_INFO = TMPSTR
               MUTEXUNLOCK MT_CTRL_INFO
          END IF
          LINE DRAWING_DEST, (X,Y)-(X+GDATA.W-BORDER_SIZE-1,Y+LINE_H-1),BACKGROUND,BF

          'TEXT PRINTING
          IF GDATA.TEXT.UPDATED THEN
               FILENAME = WF_NAMES[I]
               J = INSTRREV(FILENAME,".")
               IF J THEN FILENAME = MID(FILENAME,1,J-1)
               DURATION = S2TXT(WF_DURATIONS[I])
               TMPSTR   = FILENAME & " (" & SCHAN_NAME(WF_CHANNELS[I]) & ", " & DURATION & ")"
               IF (B < Controls[ID]->NB_IMAGES) ANDALSO (Controls[ID]->IMAGE[B] > 0) THEN
                    DIM AS I32 F2 = GDATA.TEXT.FONT_SIZE-3
                    FLOOR(F2,MIN_FONT_SIZE)
                    LINE Controls[ID]->IMAGE[B],(0,0)-(W-1,GDATA.TEXT.FONT_SIZE),0,BF
                    PrintFT(Controls[ID]->IMAGE[B],GRID_STEP,GRID_STEP-1,0,SCHAN_TAG(WF_CHANNELS[I]), _
                              MainFont.Font_hdl,F2,FOREGROUND)
                    PrintFT(Controls[ID]->IMAGE[B],6*GRID_STEP,GRID_STEP-1,0,DURATION, _
                              MainFont.Font_hdl,F2,FOREGROUND)
                    PrintFT(Controls[ID]->IMAGE[B],20*GRID_STEP,0,ICON_SIZE+GRID_STEP,FILENAME, _
                              MainFont.Font_hdl,GDATA.TEXT.FONT_SIZE,FOREGROUND)
               END IF
          END IF
          'DRAW TEXT IMAGE
          IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN _
               PUT DRAWING_DEST,(X,Y+Y0), Controls[ID]->IMAGE[B], ALPHA
          'STATUS ICON
          C = IIF(WF_STATUS[I] = WFS_RESTRICTED,1,IIF(WF_ISNODATA[I],2,IIF(WF_SEL_ID = I,0,-1)))
          IF C > -1 THEN PUT DRAWING_DEST,(X+W-ICON_SIZE-3,Y+Y0-1),Controls[ID]->IMAGE[C], ALPHA
          Y += LINE_H
          B += 1
     NEXT I

     GLIST_BOTTOM_CODE()
     
     IF WF_STATUS > 0    THEN DELETE[] WF_STATUS
     IF WF_CHANNELS > 0  THEN DELETE[] WF_CHANNELS
     IF WF_ISNODATA > 0  THEN DELETE[] WF_ISNODATA
     IF WF_DURATIONS > 0 THEN DELETE[] WF_DURATIONS
     IF WF_NAMES > 0     THEN DELETE[] WF_NAMES

     RETURN 0
END FUNCTION

FUNCTION gctrl_param_list     (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     GLIST_VARIABLES()
     DIM AS I32     C
     
     'MUTEXLOCK 'DOESN'T MATTER BECAUSE THE LIST USED ALWAYS HAS 16 LINES
     list_size = SOUNDRA.PARAM_LIST_SIZE
     'MUTEXUNLOCK

     GLIST_TOP_CODE(4)

     'DRAWING LOOP
     FOR I = start TO finish STEP S
          'BACKGROUND
          BACKGROUND = alt_line_clr(I,SWATCH0.LIST_BG)
          FOREGROUND = SWATCH0.LIST_FG
          IF I = GDATA.TEXT.si     THEN           'SELECTED (PRIORITY OVER HOVER)
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          END IF
          IF I = GDATA.TEXT.hi THEN           'HOVER
               IF I <> GDATA.TEXT.si THEN
                    BACKGROUND = SWATCH0.LIST_BG_HL
                    FOREGROUND = SWATCH0.LIST_FG_HL
               END IF
               TMPSTR = ""
               'MUTEXLOCK   
               TMPSTR = SOUNDRA.PARAM_LIST(I).LABEL
               'MUTEXUNLOCK 
               MUTEXLOCK   MT_CTRL_INFO
               Controls[ID]->CTRL_INFO = TMPSTR
               MUTEXUNLOCK MT_CTRL_INFO
          END IF
          IF SOUNDRA.PARAM_LIST(I).DISABLED THEN BACKGROUND = alt_line_clr(I,RGB(100,0,160))
          LINE DRAWING_DEST, (X,Y)-(X+GDATA.W-BORDER_SIZE-1,Y+LINE_H-1),BACKGROUND,BF

          'TEXT PRINTING
          IF GDATA.TEXT.UPDATED THEN
               TMPSTR = ""
               'MUTEXLOCK
               TMPSTR = SOUNDRA.PARAM_LIST(I).LABEL
               'MUTEXUNLOCK
               IF (B < Controls[ID]->NB_IMAGES) ANDALSO (Controls[ID]->IMAGE[B] > 0) THEN
                    LINE Controls[ID]->IMAGE[B],(0,0)-(W-1,GDATA.TEXT.FONT_SIZE),0,BF
                    PrintFT(Controls[ID]->IMAGE[B],ICON_SIZE+GRID_STEP+GRID_STEP,0,0,TMPSTR, _
                                 MainFont.Font_hdl,GDATA.TEXT.FONT_SIZE,FOREGROUND)
               END IF
          END IF
          'DRAW ICON
          IF SOUNDRA.PARAM_LIST(I).ISPORT THEN
               C = 1+SOUNDRA.PARAM_LIST(I).CONNECTED
          ELSE
               IF SOUNDRA.PARAM_LIST(I).ISMONO AND NOT(SOUNDRA.PARAM_LIST(I).ISPORT) THEN
                    C = 3
               ELSE
                    C = 2
               END IF
          END IF
          ACETATE_TRANSFER(Controls[ID]->IMAGE[C],X+GRID_STEP,Y)
          'DRAW TEXT IMAGE
          IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN _
               PUT DRAWING_DEST,(X,Y+Y0),Controls[ID]->IMAGE[B], ALPHA
          Y += LINE_H
          B += 1
     NEXT I
     
     GLIST_BOTTOM_CODE()
     RETURN 0
END FUNCTION

FUNCTION gctrl_shape_list     (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     GLIST_VARIABLES()
     
     list_size = SOUNDRA.NB_GENERATORS
     
     GLIST_TOP_CODE(0)
     
     'DRAWING LOOP
     FOR I  = start TO finish STEP S
          'BACKGROUND
          BACKGROUND = alt_line_clr(I,SWATCH0.LIST_BG)
          FOREGROUND = SWATCH0.LIST_FG
          IF I = GDATA.TEXT.si     THEN           'SELECTED (PRIORITY OVER HOVER)
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          END IF
          IF I = GDATA.TEXT.hi THEN           'HOVER
               IF I <> GDATA.TEXT.si THEN
                    BACKGROUND = SWATCH0.LIST_BG_HL
                    FOREGROUND = SWATCH0.LIST_FG_HL
               END IF
               TMPSTR = ""
               IF I < SOUNDRA.NB_GENERATORS THEN TMPSTR = SOUNDRA.GENERATOR_NAME(I)
               MUTEXLOCK   MT_CTRL_INFO
               Controls[ID]->CTRL_INFO = TMPSTR
               MUTEXUNLOCK MT_CTRL_INFO
          END IF
          LINE DRAWING_DEST, (X,Y)-(X+GDATA.W-BORDER_SIZE-1,Y+LINE_H-1),BACKGROUND,BF
          'TEXT PRINTING
          IF GDATA.TEXT.UPDATED THEN
               TMPSTR = ""
               IF I < SOUNDRA.NB_GENERATORS THEN TMPSTR = SOUNDRA.GENERATOR_NAME(I)
               IF (B < Controls[ID]->NB_IMAGES) ANDALSO (Controls[ID]->IMAGE[B] > 0) THEN
                    LINE Controls[ID]->IMAGE[B],(0,0)-(W-1,GDATA.TEXT.FONT_SIZE),0,BF
                    PrintFT(Controls[ID]->IMAGE[B],GRID_STEP,0,0,TMPSTR, _
                              MainFont.Font_hdl,GDATA.TEXT.FONT_SIZE,FOREGROUND)
               END IF
          END IF
          'DRAW TEXT IMAGE
          IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN _
               PUT DRAWING_DEST,(X,Y+Y0), Controls[ID]->IMAGE[B], ALPHA
          Y += LINE_H
          B += 1
     NEXT I
     
     GLIST_BOTTOM_CODE()
     RETURN 0
END FUNCTION

FUNCTION gctrl_filter_list    (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     GLIST_VARIABLES()
     DIM AS I32               J,C
     DIM AS TXT               FILENAME
     DIM AS SOUNDRA.MODULE    PTR SEL_PTR
     DIM AS _WF_CATALOG       PTR WF_PTR
     
     MUTEXLOCK   SOUNDRA.LI_MODULES.MUTEX
     SEL_PTR = SOUNDRA.SELECTED_MODULE
     IF SEL_PTR THEN WF_PTR = SEL_PTR->WF_PTR
     MUTEXUNLOCK SOUNDRA.LI_MODULES.MUTEX
     
     MUTEXLOCK   LI_WF_Filter.MUTEX
     list_size = LI_WF_Filter.LENGTH
     MUTEXUNLOCK LI_WF_Filter.MUTEX
     
     GLIST_TOP_CODE(3)
     
     MUTEXLOCK   LI_WF_Filter.MUTEX
     'DRAWING LOOP
     FOR I = start TO finish STEP S
          'BACKGROUND
          BACKGROUND = alt_line_clr(I,SWATCH0.LIST_BG)
          FOREGROUND = SWATCH0.LIST_FG
          IF I = GDATA.TEXT.si     THEN           'SELECTED (PRIORITY OVER HOVER)
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          END IF
          IF I = GDATA.TEXT.hi THEN           'HOVER
               IF I <> GDATA.TEXT.si THEN
                    BACKGROUND = SWATCH0.LIST_BG_HL
                    FOREGROUND = SWATCH0.LIST_FG_HL
               END IF
               IF (WF_Filter[I] > 0) THEN
                    FILENAME = WF_Filter[I]->FileName
               END IF
               MUTEXLOCK   MT_CTRL_INFO
               Controls[ID]->CTRL_INFO = FILENAME
               MUTEXUNLOCK MT_CTRL_INFO
          END IF
          LINE DRAWING_DEST, (X,Y)-(X+GDATA.W-BORDER_SIZE-1,Y+LINE_H-1),BACKGROUND,BF

          'TEXT PRINTING
          IF GDATA.TEXT.UPDATED THEN
               TMPSTR = ""
               IF (WF_Filter[I] > 0) THEN
                    FILENAME = WF_Filter[I]->FileName
                    J = INSTRREV(FILENAME,".")
                    IF J THEN FILENAME = MID(FILENAME,1,J-1)
               END IF
               IF (B < Controls[ID]->NB_IMAGES) ANDALSO (Controls[ID]->IMAGE[B] > 0) THEN
                    LINE Controls[ID]->IMAGE[B],(0,0)-(W-1,GDATA.TEXT.FONT_SIZE),0,BF
                    PrintFT(Controls[ID]->IMAGE[B],GRID_STEP,0,ICON_SIZE+GRID_STEP,FILENAME, _
                              MainFont.Font_hdl,GDATA.TEXT.FONT_SIZE,FOREGROUND)
               END IF
          END IF
          'DRAW TEXT IMAGE
          IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN _
               PUT DRAWING_DEST,(X,Y+Y0), Controls[ID]->IMAGE[B], ALPHA
          'STATUS ICON
          C = IIF(WF_Filter[I]->STATUS = WFS_RESTRICTED,1,IIF(WF_Filter[I]->WaveFile.AudioData = _
               0,2,IIF((WF_PTR > 0) AND (WF_Filter[I] = WF_PTR),0,-1)))
          IF C > -1 THEN PUT DRAWING_DEST,(X+W-ICON_SIZE-3,Y+Y0-1),Controls[ID]->IMAGE[C], ALPHA
          Y += LINE_H
          B += 1
     NEXT I
     MUTEXUNLOCK LI_WF_Filter.MUTEX
     
     GLIST_BOTTOM_CODE()
     RETURN 0
END FUNCTION

FUNCTION gctrl_melody_list    (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     GLIST_VARIABLES()
     DIM AS I32               J,C
     DIM AS F32               D
     DIM AS TXT               FILENAME, CHANNELS, DURATION
     DIM AS SOUNDRA.MODULE    PTR SEL_PTR
     DIM AS _WF_CATALOG       PTR WF_PTR

     MUTEXLOCK   SOUNDRA.LI_MODULES.MUTEX
     SEL_PTR = SOUNDRA.SELECTED_MODULE
     IF SEL_PTR THEN WF_PTR = SEL_PTR->WF_PTR
     MUTEXUNLOCK SOUNDRA.LI_MODULES.MUTEX
     
     MUTEXLOCK   LI_WF_Melody.MUTEX
     list_size = LI_WF_Melody.LENGTH
     MUTEXUNLOCK LI_WF_Melody.MUTEX
     
     GLIST_TOP_CODE(3)

     MUTEXLOCK   LI_WF_Melody.MUTEX
     'DRAWING LOOP
     FOR I = start TO finish STEP S
          'BACKGROUND
          BACKGROUND = alt_line_clr(I,SWATCH0.LIST_BG)
          FOREGROUND = SWATCH0.LIST_FG
          IF I = GDATA.TEXT.si     THEN           'SELECTED (PRIORITY OVER HOVER)
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          END IF
          IF I = GDATA.TEXT.hi THEN           'HOVER
               IF I <> GDATA.TEXT.si THEN
                    BACKGROUND = SWATCH0.LIST_BG_HL
                    FOREGROUND = SWATCH0.LIST_FG_HL
               END IF
               IF (WF_Melody[I] > 0) THEN
                    FILENAME = WF_Melody[I]->FileName
                    D        = WF_Melody[I]->Duration
               END IF
               DURATION = S2TXT(D)
               TMPSTR   = FILENAME & " (" & DURATION & ")"
               MUTEXLOCK   MT_CTRL_INFO
               Controls[ID]->CTRL_INFO = TMPSTR
               MUTEXUNLOCK MT_CTRL_INFO
          END IF
          LINE DRAWING_DEST, (X,Y)-(X+GDATA.W-BORDER_SIZE-1,Y+LINE_H-1),BACKGROUND,BF
          'TEXT PRINTING
          IF GDATA.TEXT.UPDATED THEN
               TMPSTR = ""
               IF (WF_Melody[I] > 0) THEN
                    FILENAME = WF_Melody[I]->FileName
                    J = INSTRREV(FILENAME,".")
                    IF J THEN FILENAME = MID(FILENAME,1,J-1)
                    D = WF_Melody[I]->Duration
               END IF
               DURATION = S2TXT(D)
               IF (B < Controls[ID]->NB_IMAGES) ANDALSO (Controls[ID]->IMAGE[B] > 0) THEN
                    LINE Controls[ID]->IMAGE[B],(0,0)-(W-1,GDATA.TEXT.FONT_SIZE),0,BF
                    PrintFT(Controls[ID]->IMAGE[B],GRID_STEP,0,ICON_SIZE+GRID_STEP,FILENAME, _
                         MainFont.Font_hdl,GDATA.TEXT.FONT_SIZE,FOREGROUND)
               END IF
          END IF
          'DRAW TEXT IMAGE
          IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN _
              PUT DRAWING_DEST,(X,Y+Y0), Controls[ID]->IMAGE[B], ALPHA
          'STATUS ICON
          C = IIF(WF_Melody[I]->STATUS = WFS_RESTRICTED,1,IIF(WF_Melody[I]->WaveFile.AudioData = _
              0,2,IIF((WF_PTR > 0) AND (WF_Melody[I] = WF_PTR),0,-1)))
          IF C > -1 THEN PUT DRAWING_DEST,(X+W-ICON_SIZE-3,Y+Y0-1),Controls[ID]->IMAGE[C], ALPHA
          Y += LINE_H
          B += 1
     NEXT I
     MUTEXUNLOCK LI_WF_Melody.MUTEX
     
     GLIST_BOTTOM_CODE()
     RETURN 0
END FUNCTION

FUNCTION gctrl_mdevs_list     (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     GLIST_VARIABLES()

     list_size = NB_MIDI_DEVICES_MAX+1
     
     GLIST_TOP_CODE(0)

     'DRAWING LOOP
     FOR I  = start TO finish STEP S
          'BACKGROUND
          BACKGROUND = alt_line_clr(I,SWATCH0.LIST_BG)
          FOREGROUND = SWATCH0.LIST_FG
          IF I = GDATA.TEXT.si     THEN           'SELECTED (PRIORITY OVER HOVER)
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          END IF
          IF I = GDATA.TEXT.hi THEN           'HOVER
               IF I <> GDATA.TEXT.si THEN
                    BACKGROUND = SWATCH0.LIST_BG_HL
                    FOREGROUND = SWATCH0.LIST_FG_HL
               END IF
               TMPSTR = ""
               IF I = 0 THEN
                    TMPSTR = STR_DEV_ANY
               ELSE
                    MUTEXLOCK   SOUNDRA.MT_MIDICC
                    TMPSTR = SOUNDRA.MIDI_MAP[I-1]->DEVICE_NAME
                    MUTEXUNLOCK SOUNDRA.MT_MIDICC
                    IF TMPSTR = "" THEN TMPSTR = STR_DEV_NONE
               END IF
               MUTEXLOCK   MT_CTRL_INFO
               Controls[ID]->CTRL_INFO = TMPSTR
               MUTEXUNLOCK MT_CTRL_INFO
          END IF
          LINE DRAWING_DEST, (X,Y)-(X+GDATA.W-BORDER_SIZE-1,Y+LINE_H-1),BACKGROUND,BF

          'TEXT PRINTING
          IF GDATA.TEXT.UPDATED THEN
               'GET THE STRING
               TMPSTR = ""
               IF I = 0 THEN
                    TMPSTR = STR_DEV_ANY
               ELSE
                    MUTEXLOCK   SOUNDRA.MT_MIDICC
                    TMPSTR = SOUNDRA.MIDI_MAP[I-1]->DEVICE_NAME
                    MUTEXUNLOCK SOUNDRA.MT_MIDICC
                    IF TMPSTR = "" THEN TMPSTR = STR_DEV_NONE
               END IF
               'DRAW TEXT ONTO BUFFER
               IF (B < Controls[ID]->NB_IMAGES) ANDALSO (Controls[ID]->IMAGE[B] > 0) THEN
                    LINE Controls[ID]->IMAGE[B],(0,0)-(W-1,GDATA.TEXT.FONT_SIZE),0,BF
                    PrintFT(Controls[ID]->IMAGE[B],GRID_STEP,0,0,TMPSTR, _
                              MainFont.Font_hdl,GDATA.TEXT.FONT_SIZE,FOREGROUND)
               END IF
          END IF
          'PRINT TEXT IMAGE
          IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN _
               PUT DRAWING_DEST,(X,Y + Y0), Controls[ID]->IMAGE[B], ALPHA
          Y += LINE_H
          B += 1
     NEXT I
     
     GLIST_BOTTOM_CODE()
     RETURN 0
END FUNCTION
FUNCTION gctrl_MIDI_DEVS_list    (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     GLIST_VARIABLES()
     DIM AS I32     J,C,PID
     DIM AS TXT     NUM_TXT, DEV_NAME
     
     list_size = NB_MIDI_DEVICES_MAX

     GLIST_TOP_CODE(2)
     
     'DRAWING LOOP
     FOR I = start TO finish STEP S
          'BACKGROUND
          BACKGROUND = alt_line_clr(I,SWATCH0.LIST_BG)
          FOREGROUND = SWATCH0.LIST_FG
          IF I = GDATA.TEXT.si     THEN           'SELECTED (PRIORITY OVER HOVER)
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          END IF
          IF I = GDATA.TEXT.hi THEN               'HOVER
               IF I <> GDATA.TEXT.si THEN
                    BACKGROUND = SWATCH0.LIST_BG_HL
                    FOREGROUND = SWATCH0.LIST_FG_HL
               END IF
               '¤¤¤#278: "DEVICE {$}: "
               TMPSTR = LNG_SET_EXT(278,"DEVICE {$}: ")
               TMPSTR  = TXTINSERT(TMPSTR,STR(I))
               NUM_TXT = TMPSTR
               MUTEXLOCK   SOUNDRA.MT_MIDICC
               DEV_NAME = SOUNDRA.MIDI_MAP[I]->DEVICE_NAME
               MUTEXUNLOCK SOUNDRA.MT_MIDICC
               IF DEV_NAME = "" THEN DEV_NAME = STR_DEV_NONE
               MUTEXLOCK   MT_CTRL_INFO
               Controls[ID]->CTRL_INFO = NUM_TXT & "   " & DEV_NAME
               MUTEXUNLOCK MT_CTRL_INFO
          END IF
          LINE DRAWING_DEST, (X,Y)-(X+GDATA.W-BORDER_SIZE-1,Y+LINE_H-1),BACKGROUND,BF

          'TEXT & ICONS PRINTING
          IF GDATA.TEXT.UPDATED THEN
               NUM_TXT  = STR(I)
               MUTEXLOCK   SOUNDRA.MT_MIDICC
               DEV_NAME = SOUNDRA.MIDI_MAP[I]->DEVICE_NAME
               MUTEXUNLOCK SOUNDRA.MT_MIDICC
               IF DEV_NAME = "" THEN DEV_NAME = STR_DEV_NONE
               'DRAW ONTO TEXT IMAGE
               IF (B < Controls[ID]->NB_IMAGES) ANDALSO (Controls[ID]->IMAGE[B] > 0) THEN
                    LINE Controls[ID]->IMAGE[B],(0,0)-(W-1,GDATA.TEXT.FONT_SIZE),0,BF
                    PrintFT(Controls[ID]->IMAGE[B],GRID_STEP,0,0,NUM_TXT, _
                              MainFont.Font_hdl,GDATA.TEXT.FONT_SIZE,FOREGROUND)
                    PrintFT(Controls[ID]->IMAGE[B],8*GRID_STEP,0,0,DEV_NAME, _
                              MainFont.Font_hdl,GDATA.TEXT.FONT_SIZE,FOREGROUND)
               END IF
          END IF
          'PRINT TEXT IMAGE
          IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN _
               PUT DRAWING_DEST,(X,Y+Y0), Controls[ID]->IMAGE[B], ALPHA
          'ICONS (CONNECTION STATE)
          C = -1
          MUTEXLOCK   SOUNDRA.MT_MIDICC
          IF SOUNDRA.MIDI_MAP[I] > 0 ANDALSO (TRIM(SOUNDRA.MIDI_MAP[I]->DEVICE_NAME) <> "") THEN _
             C = IIF(SOUNDRA.MIDI_MAP[I]->CONNECTED=TRUE,0,1)
          MUTEXUNLOCK SOUNDRA.MT_MIDICC
          IF C > -1 THEN PUT DRAWING_DEST,(X+W-ICON_SIZE-3,Y+Y0-2),Controls[ID]->IMAGE[C], ALPHA
          Y += LINE_H
          B += 1
     NEXT I
     
     GLIST_BOTTOM_CODE()
     RETURN 0
END FUNCTION
FUNCTION gctrl_MIDICC_list    (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     GLIST_VARIABLES()
     DIM AS I32               J,C,PID
     DIM AS I32               CHAN = SOUNDRA.MIDICC_CHAN
     STATIC AS I32            CT, MIDICT
     DIM AS TXT               NUM_TXT, MOD_NAME
     DIM AS SOUNDRA.MODULE    PTR MOD_PTR
     
     list_size = NB_MIDI_CONTROLS_MAX+1
     
     GLIST_TOP_CODE(4)
     
     'DRAWING LOOP
     FOR I  = start TO finish STEP S
          'BACKGROUND
          BACKGROUND = alt_line_clr(I,SWATCH0.LIST_BG)
          FOREGROUND = SWATCH0.LIST_FG
          IF I = GDATA.TEXT.si     THEN           'SELECTED (PRIORITY OVER HOVER)
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          END IF
          IF I = GDATA.TEXT.hi THEN               'HOVER
               IF I <> GDATA.TEXT.si THEN
                    BACKGROUND = SWATCH0.LIST_BG_HL
                    FOREGROUND = SWATCH0.LIST_FG_HL
               END IF
               IF I = 0 THEN
                    NUM_TXT  = ""
                    '¤¤¤#279: "CLICK TO GO BACK"
                    TMPSTR = LNG_SET_EXT(279,"CLICK TO GO BACK")
                    MOD_NAME = TMPSTR
               ELSE
                    '¤¤¤#280: "CONTROL #{$}: "
                    TMPSTR = LNG_SET_EXT(280,"CONTROL #{$}: ")
                    TMPSTR   = TXTINSERT(TMPSTR,STR(I-1))
                    NUM_TXT  = TMPSTR
                    MOD_NAME = STR_DEV_NA
                    MUTEXLOCK   SOUNDRA.MT_MIDICC
                    IF SOUNDRA.MIDI_MAP[SOUNDRA.MIDICC_MAP_ID] > 0 THEN
                         CT       = SOUNDRA.MIDI_MAP[SOUNDRA.MIDICC_MAP_ID]->LINK(I-1,CHAN).MODCT
                         PID      = SOUNDRA.MIDI_MAP[SOUNDRA.MIDICC_MAP_ID]->LINK(I-1,CHAN).PID
                         MOD_PTR  = SOUNDRA.MIDI_MAP[SOUNDRA.MIDICC_MAP_ID]->LINK(I-1,CHAN).MOD_PTR
                    END IF
                    MUTEXUNLOCK SOUNDRA.MT_MIDICC
                    IF CT = SOUNDRA.MIDI_CONTROL_FREE THEN
                         MOD_NAME = STR_DEV_ANYCON
                    ELSEIF CT > SOUNDRA.MIDI_CONTROL_UNMAPPED THEN
                         IF PID = -1 THEN
                              MOD_NAME = STR_DEV_INVALID
                         ELSEIF CT = SOUNDRA.MIDI_CONTROL_SEMI THEN
                              '¤¤¤#281: "PORT #{$} of selected module."
                              TMPSTR = LNG_SET_EXT(281,"PORT #{$} of selected module.")
                              TMPSTR   = TXTINSERT(TMPSTR,STR(PID))
                              MOD_NAME = TMPSTR
                         ELSEIF CT = SOUNDRA.MIDI_CONTROL_FIXED THEN
                              '¤¤¤#282: "PORT #"
                              TMPSTR = LNG_SET_EXT(282,"PORT #")
                              TMPSTR  &= STR(PID)
                              MOD_NAME = TMPSTR
                              IF MOD_PTR > 0 THEN
                                   MOD_NAME &= " (" & MOD_PTR->PARAM(PID).VarName & ") of "
                                   MOD_NAME &= MOD_PTR->Abbrev & " #"
                                   MOD_NAME &= STR(MOD_PTR->TYPE_ID)
                              ELSE
                                   MOD_NAME = STR_DEV_INVALID
                              END IF
                         END IF
                    END IF
               END IF
               MUTEXLOCK   MT_CTRL_INFO
               Controls[ID]->CTRL_INFO = NUM_TXT & "   " & MOD_NAME
               MUTEXUNLOCK MT_CTRL_INFO
          END IF
          LINE DRAWING_DEST, (X,Y)-(X+GDATA.W-BORDER_SIZE-1,Y+LINE_H-1),BACKGROUND,BF

          'TEXT & ICONS PRINTING
          IF GDATA.TEXT.UPDATED THEN
               IF I = 0 THEN
                    NUM_TXT  = ""
                    MUTEXLOCK   SOUNDRA.MT_MIDICC
                    IF SOUNDRA.MIDI_MAP[SOUNDRA.MIDICC_MAP_ID] > 0 THEN _
                         MOD_NAME = SOUNDRA.MIDI_MAP[SOUNDRA.MIDICC_MAP_ID]->DEVICE_NAME
                    MUTEXUNLOCK SOUNDRA.MT_MIDICC
               ELSE
                    NUM_TXT  = STR(I-1) & " : "
                    MOD_NAME = STR_DEV_NA
                    MUTEXLOCK   SOUNDRA.MT_MIDICC
                    IF SOUNDRA.MIDI_MAP[SOUNDRA.MIDICC_MAP_ID] > 0 THEN
                         CT       = SOUNDRA.MIDI_MAP[SOUNDRA.MIDICC_MAP_ID]->LINK(I-1,CHAN).MODCT
                         PID      = SOUNDRA.MIDI_MAP[SOUNDRA.MIDICC_MAP_ID]->LINK(I-1,CHAN).PID
                         MOD_PTR  = SOUNDRA.MIDI_MAP[SOUNDRA.MIDICC_MAP_ID]->LINK(I-1,CHAN).MOD_PTR
                    END IF
                    MUTEXUNLOCK SOUNDRA.MT_MIDICC
                    IF CT = SOUNDRA.MIDI_CONTROL_FREE THEN
                         MOD_NAME = STR_DEV_ANYCON
                    ELSEIF CT > SOUNDRA.MIDI_CONTROL_UNMAPPED THEN
                         IF PID = -1 THEN
                              MOD_NAME = STR_DEV_INVALID
                         ELSEIF CT = SOUNDRA.MIDI_CONTROL_SEMI THEN
                              '¤¤¤#283: "PORT #{$} of selected module."
                              TMPSTR = LNG_SET_EXT(283,"PORT #{$} of selected module.")
                              TMPSTR   = TXTINSERT(TMPSTR,STR(PID))
                              MOD_NAME = TMPSTR
                         ELSEIF CT = SOUNDRA.MIDI_CONTROL_FIXED THEN
                              IF MOD_PTR > 0 THEN
                                   '¤¤¤#284: "PORT #{$} ({$}) OF {$}"
                                   TMPSTR = LNG_SET_EXT(284,"PORT #{$} ({$}) OF {$}")
                                   TMPSTR   = TXTINSERT(TMPSTR,STR(PID))
                                   TMPSTR   = TXTINSERT(TMPSTR,MOD_PTR->PARAM(PID).VarName)
                                   TMPSTR   = TXTINSERT(TMPSTR,MOD_PTR->Abbrev)
                                   MOD_NAME = TMPSTR  & " #" & STR(MOD_PTR->TYPE_ID)
                              ELSE
                                   MOD_NAME = STR_DEV_INVALID
                              END IF
                         END IF
                    END IF
               END IF
               'DRAW ONTO TEXT IMAGE
               IF (B < Controls[ID]->NB_IMAGES) ANDALSO (Controls[ID]->IMAGE[B] > 0) THEN
                    LINE Controls[ID]->IMAGE[B],(0,0)-(W-1,GDATA.TEXT.FONT_SIZE),0,BF
                    PrintFT(Controls[ID]->IMAGE[B],GRID_STEP,0,0,NUM_TXT, _
                              MainFont.Font_hdl,GDATA.TEXT.FONT_SIZE,FOREGROUND)
                    PrintFT(Controls[ID]->IMAGE[B],8*GRID_STEP,0,0,MOD_NAME, _
                              MainFont.Font_hdl,GDATA.TEXT.FONT_SIZE,FOREGROUND)
               END IF
          END IF
          'PRINT TEXT IMAGE
          IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN _
               PUT DRAWING_DEST,(X,Y+Y0), Controls[ID]->IMAGE[B], ALPHA
          'ICONS
          C = 0 'BACK
          IF I > 0 THEN
               MUTEXLOCK   SOUNDRA.MT_MIDICC
               IF SOUNDRA.MIDI_MAP[SOUNDRA.MIDICC_MAP_ID] > 0 THEN _
                    MIDICT = SOUNDRA.MIDI_MAP[SOUNDRA.MIDICC_MAP_ID]->LINK(I-1,CHAN).MIDICT
               MUTEXUNLOCK SOUNDRA.MT_MIDICC
               C = -1
               IF     MIDICT > MIDI_BUTTONV THEN
                    C = 3
               ELSEIF MIDICT > MIDI_STD     THEN
                    C = 2
               ELSEIF MIDICT > MIDI_UNKNOWN THEN
                    C = 1
               END IF
          END IF
          IF C > -1 THEN PUT DRAWING_DEST,(X+W-ICON_SIZE-3,Y+Y0-1),Controls[ID]->IMAGE[C], ALPHA
          Y += LINE_H
          B += 1
     NEXT I
     
     GLIST_BOTTOM_CODE()
     RETURN 0
END FUNCTION

'------------------------------------------------------------------------------------------------------------
' SETTINGS :: TUNING
FUNCTION gctrl_tuning_name    (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     STATIC AS IOS  MODIFIED,CHANGE
     IF (Controls[ID]->NB_IMAGES > 0) ANDALSO (Controls[ID]->IMAGE[0] > 0) THEN
          DIM AS IOS  X,Y, W,H, OFFSET
          DIM AS TXT  TMPSTR = ""
          MUTEXLOCK   MT_TUNINGS(TUNING_COPY)
          CHANGE   = NOT(MODIFIED = TUNINGS(TUNING_COPY).MODIFIED)
          MODIFIED = TUNINGS(TUNING_COPY).MODIFIED
          MUTEXUNLOCK MT_TUNINGS(TUNING_COPY)
          IF GDATA.TEXT.UPDATED OR CHANGE THEN
               IF MODIFIED = TRUE THEN 
                    '¤¤¤#285: " (modifications not saved)"
                    TMPSTR = LNG_SET_EXT(285," (modifications not saved)")
               END IF
               TMPSTR = GDATA.TEXT.CONTENT & TMPSTR
               'TEXT ALIGNMENT
               GDATA.TEXT.TEXT_WIDTH = GetTXT_W(TMPSTR,MainFont,GDATA.TEXT.FONT_SIZE)
               IMAGEINFO(Controls[ID]->IMAGE[0],W,H)
               CEIL(GDATA.TEXT.TEXT_WIDTH,W)
               Controls[ID]->text.text_width = GDATA.TEXT.TEXT_WIDTH '!!!
               X      = 0
               Y      = .5*(H - GDATA.text.font_size)
               OFFSET = W - GDATA.TEXT.TEXT_WIDTH
               IF     GDATA.text.align = ALIGN_RIGHT THEN
                    X += OFFSET
               ELSEIF GDATA.text.align = ALIGN_CENTER THEN
                    X += .5*OFFSET
               END IF
               'PATCH BG AND PRINT TEXT
               LINE Controls[ID]->IMAGE[0],(0,0)-(W-1,H-1),0,BF
               PrintFT(Controls[ID]->IMAGE[0],X,Y,0,TMPSTR,MainFont.Font_hdl,_
                    GDATA.TEXT.FONT_SIZE,GDATA.TEXT.FONT_CLR)
          END IF
          X = GDATA.X + BORDER_SIZE
          Y = GDATA.Y + BORDER_SIZE
          ACETATE_TRANSFER(Controls[ID]->IMAGE[0],X,Y)
     END IF
     RETURN 0
END FUNCTION

FUNCTION gctrl_tuning_scale   (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM    AS I32       I,N, Y,H, XK, H2
     DIM    AS F32       X,W, WK,WZ
     DIM    AS RGB_PX    TMP_RGB
     DIM    AS HSB_PX    TMP_HSB = TYPE(1,1,1)
     
     MUTEXLOCK MT_TUNINGS(TUNING_COPY)
     N  = TUNINGS(TUNING_COPY).NB_KEYS
     X  = GDATA.X
     Y  = GDATA.Y
     H  = GDATA.H
     W  = GDATA.W
     
     WK = (W - 2*BORDER_SIZE) / N       'KEY WIDTH
     FLOOR(WK,2)
     H2 = .375*H                        'SCALE HEIGHT

     FOREGROUND = SWATCH0.TEXTAREA_FG
     BACKGROUND = SWATCH0.TEXTAREA_BG
         
     X  = 0
     Y  = 0
     WZ = 0
     FOR I = 0 TO N-2
          'CALCULATIONS
          WZ = W*(TUNINGS(TUNING_COPY).KEY_ABS(I+1) - TUNINGS(TUNING_COPY).KEY_ABS(I))
          FLOOR(WZ,1)
          XK = (CSNG(I)+.5)*WK + BORDER_SIZE
          TMP_HSB.H = TUNINGS(TUNING_COPY).KEY_ABS(I) - 1
          TMP_RGB   = HSB2RGB(TMP_HSB)
          'ZONE
          LINE DRAWING_DEST,(GDATA.X+X,GDATA.Y+Y)-(GDATA.X+X+WZ-1,GDATA.Y+Y+H2-1),TMP_RGB.CLR,BF
          'SEPARATOR
          LINE DRAWING_DEST,(GDATA.X+X,GDATA.Y+Y)-(GDATA.X+X,GDATA.Y+Y+H2-1),FOREGROUND
          'CONNECTOR
          LINE DRAWING_DEST,(GDATA.X+X,GDATA.Y+Y+H2)-(GDATA.X+XK,GDATA.Y+Y+H-1),FOREGROUND
          X += WZ
          CEIL(X,W-1)
     NEXT I
     'LAST KEY
     'CALCULATIONS
     WZ = W*(2 - TUNINGS(TUNING_COPY).KEY_ABS(N-1))
     MUTEXUNLOCK MT_TUNINGS(TUNING_COPY)
     FLOOR(WZ,1)
     XK = (N-.5)*WK + BORDER_SIZE
     TMP_HSB.H = TUNINGS(TUNING_COPY).KEY_ABS(N-1) - 1
     TMP_RGB   = HSB2RGB(TMP_HSB)
     'ZONE
     LINE DRAWING_DEST,(GDATA.X+X,GDATA.Y+Y)-(GDATA.X+X+WZ-1,GDATA.Y+Y+H2-1),TMP_RGB.CLR,BF
     'SEPARATOR
     LINE DRAWING_DEST,(GDATA.X+X,GDATA.Y+Y)-(GDATA.X+X,GDATA.Y+Y+H2-1),FOREGROUND
     'CONNECTOR
     LINE DRAWING_DEST,(GDATA.X+X,GDATA.Y+Y+H2)-(GDATA.X+XK,GDATA.Y+Y+H-1),FOREGROUND

     RETURN 0
END FUNCTION

FUNCTION gctrl_tuning_keys    (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM    AS I32  I,R,X2,X,Y,N,CHAR_W, TEXT_SIZE
     DIM    AS F32  W2
     'CALCULATIONS
     MUTEXLOCK MT_TUNINGS(TUNING_COPY)
     N  = TUNINGS(TUNING_COPY).NB_KEYS
     MUTEXUNLOCK MT_TUNINGS(TUNING_COPY)
     
     'AUTO FONT-SIZE
     W2 = (GDATA.W-BORDER_SIZE*2) / N 'BUTTON WIDTH
     FLOOR(W2,2)
     CHAR_W = GetTXT_W("WW", MainFont, GDATA.text.font_size)
     DO WHILE CHAR_W > (W2 - BORDER_SIZE) AND GDATA.text.font_size > 8
          GDATA.text.font_size -= 1
          CHAR_W = GetTXT_W("WW", MainFont, GDATA.text.font_size)
     LOOP
     Controls[ID]->text.font_size = GDATA.text.font_size '!!!
     TEXT_SIZE  = GDATA.text.font_size
     
     'COLOR / BG
     FOREGROUND = SWATCH0.BUTTON_FG
     BACKGROUND = SWATCH0.BUTTON_BG
     PATCH_BG()
     'HIGHLIGHT ZONE IF ACTIVE
     IF GDATA.text.hi > N - 1 THEN GDATA.text.hi = -1
     IF GDATA.text.hi > -1 THEN
          X = GDATA.X + BORDER_SIZE + (CSNG(GDATA.text.hi) * W2)
          Y = GDATA.Y + BORDER_SIZE
          LINE DRAWING_DEST, (X,Y)-(X+W2-1,Y+GDATA.H-BORDER_SIZE-1),SWATCH0.BUTTON_BG_ACTIVE,BF
     END IF
     'SELECTION
     IF GDATA.text.si > N - 1 THEN GDATA.text.si = -1
     IF GDATA.text.si > -1 THEN
          X = GDATA.X + BORDER_SIZE + (CSNG(GDATA.text.si) * W2)
          Y = GDATA.Y + BORDER_SIZE
          LINE DRAWING_DEST, (X,Y)-(X+W2-1,Y+GDATA.H-BORDER_SIZE-1),SWATCH0.TEXTAREA_BG_HL,BF
     END IF
     'KEY NAMES
     IF GDATA.TEXT.UPDATED THEN
          DIM AS TXT TMPSTR
          LINE Controls[ID]->IMAGE[0],(0,0)-(GDATA.W-1,GDATA.TEXT.FONT_SIZE),0,BF
          FOR I = 0 TO N - 1
               X = int(CSNG(I) * W2)
               MUTEXLOCK   MT_TUNINGS(TUNING_COPY)
               TMPSTR = TUNINGS(TUNING_COPY).KEY_NAME(I)
               MUTEXUNLOCK MT_TUNINGS(TUNING_COPY)
               PrintFT(Controls[ID]->IMAGE[0],INT(X)+2,0,0,TMPSTR, _
                       MainFont.Font_hdl,TEXT_SIZE,FOREGROUND,GLYPH_ADD)
          NEXT I
     END IF
     'VERTICAL LINES
     X = GDATA.X + BORDER_SIZE + .5*(W2 - CHAR_W) + 2
     Y = GDATA.Y + .5*(GDATA.H - GDATA.text.font_size) + 1
     PUT DRAWING_DEST,(X,Y), Controls[ID]->IMAGE[0],ADD
     Y = GDATA.Y + BORDER_SIZE
     FOR I = 1 TO N - 1
          X = GDATA.X + BORDER_SIZE + int(I * W2)
          LINE DRAWING_DEST,(X,Y)-(X+1,GDATA.Y+GDATA.H-BORDER_SIZE-1),SWATCH0.FRM_OFF,BF
     NEXT I
     'FRAME
     STYLE_FLAT_FRAME(SWATCH0.FRM_OFF)
     DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, FRAME_COLOR)
     RETURN 0
END FUNCTION
FUNCTION gctrl_tuning_sp      (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM AS I32  I,J,R,X2,X,Y,N
     DIM AS F32  W2
     DIM AS UI64 P
     'CALCULATIONS
     J  = Controls[ControlAccess[CS_TNG_SP_LIST]]->text.si '!!!
     FLOOR(J,0)
     MUTEXLOCK MT_TUNINGS(TUNING_COPY)
     N  = TUNINGS(TUNING_COPY).NB_KEYS
     P  = TUNINGS(TUNING_COPY).MODE(J)
     MUTEXUNLOCK MT_TUNINGS(TUNING_COPY)
     W2 = (GDATA.W-BORDER_SIZE*2) / N 'BUTTON WIDTH
     FLOOR(W2,2)
     FOREGROUND = SWATCH0.BUTTON_FG
     BACKGROUND = SWATCH0.FRM_OFF

     'ON/OFF BG + HIGHLIGHT
     Y = GDATA.Y + BORDER_SIZE
     FOR I = 0 TO N - 1
          X = GDATA.X + BORDER_SIZE + (CSNG(I) * W2)
          BACKGROUND = IIF(BIT(P,I) = TRUE,SWATCH0.TAB_BG_ON,SWATCH0.TAB_BG)
          IF I = GDATA.text.hi THEN BACKGROUND = SWATCH0.BUTTON_BG_ACTIVE
          LINE DRAWING_DEST,(X,Y)-(X+W2-1,GDATA.Y+GDATA.H-BORDER_SIZE-1),BACKGROUND,BF
          LINE DRAWING_DEST,(X,Y)-(X+W2-1,GDATA.Y+GDATA.H-BORDER_SIZE-1),SWATCH0.FRM_OFF,B
          X += W2
     NEXT I
     'FRAME
     STYLE_FLAT_FRAME(SWATCH0.FRM_OFF)
     DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, FRAME_COLOR)
     RETURN 0
END FUNCTION

FUNCTION gctrl_tuning_sp_list  (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     GLIST_VARIABLES()
     DIM AS _TEXTLINE    PTR MODE_NAMES
     DIM AS UI64         PTR MODES
     
     MUTEXLOCK   MT_TUNINGS(TUNING_COPY)
     list_size  = TUNINGS(TUNING_COPY).vNBSP
     N          = TUNINGS(TUNING_COPY).NB_KEYS
     MODE_NAMES = NEW _TEXTLINE[list_size]
     MODES      = NEW UI64[list_size]
     FOR I = 0 TO list_size-1
          MODE_NAMES[I] = TUNINGS(TUNING_COPY).MODE_NAME(I)
          MODES[I]      = TUNINGS(TUNING_COPY).MODE(I)
     NEXT I
     MUTEXUNLOCK MT_TUNINGS(TUNING_COPY)
     
     GLIST_TOP_CODE(0)

     'DRAWING LOOP
     FOR I = start TO finish STEP S
          'BACKGROUND
          BACKGROUND = alt_line_clr(I,SWATCH0.LIST_BG)
          FOREGROUND = SWATCH0.LIST_FG
          IF I = GDATA.TEXT.si THEN           'SELECTED (PRIORITY OVER HOVER)
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          END IF
          IF I = GDATA.TEXT.hi THEN           'HOVER
               DIM AS STRING TMPSTR
               IF I <> GDATA.TEXT.si THEN
                    BACKGROUND = SWATCH0.LIST_BG_HL
                    FOREGROUND = SWATCH0.LIST_FG_HL
               END IF
               TMPSTR = MID(BIN(MODES[I]),TNG_MAXSP-N+1)
               IF LEN(TMPSTR) < N THEN TMPSTR = STRING(N-LEN(TMPSTR),"0")
               TMPSTR = TRIM(MODE_NAMES[I]) & " :  "
               MUTEXLOCK   MT_CTRL_INFO
               Controls[ID]->CTRL_INFO = TMPSTR
               MUTEXUNLOCK MT_CTRL_INFO
          END IF
          LINE DRAWING_DEST, (X,Y)-(X+GDATA.W-BORDER_SIZE-1,Y+LINE_H-1),BACKGROUND,BF
          'TEXT PRINTING
          IF GDATA.TEXT.UPDATED THEN
               DIM AS STRING  TMPSTR
               DIM AS I32     K
               IF (B < Controls[ID]->NB_IMAGES) ANDALSO (Controls[ID]->IMAGE[B] > 0) THEN
                    LINE Controls[ID]->IMAGE[B],(0,0)-(W-1,GDATA.TEXT.FONT_SIZE),0,BF
                    TMPSTR = TRIM(MODE_NAMES[I])
                    PrintFT(Controls[ID]->IMAGE[B],GRID_STEP,0,0,TMPSTR,MainFont.Font_hdl,_
                         GDATA.TEXT.FONT_SIZE,FOREGROUND)
               END IF
          END IF
          'DRAW TEXT IMAGE
          IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN _
               PUT DRAWING_DEST,(X,Y + Y0), Controls[ID]->IMAGE[B], ALPHA
          Y += LINE_H
          B += 1
     NEXT I

     GLIST_BOTTOM_CODE()
     
     IF MODE_NAMES > 0 THEN DELETE[] MODE_NAMES
     IF MODES > 0      THEN DELETE[] MODES
     
     RETURN 0
END FUNCTION
FUNCTION gctrl_sp_list    (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     GLIST_VARIABLES()
     DIM AS _TEXTLINE    PTR MODE_NAMES
     DIM AS UI64         PTR MODES
     
     MUTEXLOCK   MT_TUNINGS(TUNING_CURRENT)
     N          = TUNINGS(TUNING_CURRENT).NB_KEYS
     list_size  = TUNINGS(TUNING_CURRENT).vNBSP
     MODE_NAMES = NEW _TEXTLINE[list_size]
     MODES      = NEW UI64[list_size]
     FOR I = 0 TO list_size-1
          MODE_NAMES[I] = TUNINGS(TUNING_CURRENT).MODE_NAME(I)
          MODES[I]      = TUNINGS(TUNING_CURRENT).MODE(I)
     NEXT I
     MUTEXUNLOCK MT_TUNINGS(TUNING_CURRENT)
     
     GLIST_TOP_CODE(0)

     'DRAWING LOOP
     FOR I = start TO finish STEP S
          'BACKGROUND
          BACKGROUND = alt_line_clr(I,SWATCH0.LIST_BG)
          FOREGROUND = SWATCH0.LIST_FG
          IF I = GDATA.TEXT.si THEN           'SELECTED (PRIORITY OVER HOVER)
               BACKGROUND = SWATCH0.BUTTON_BG_ON
               FOREGROUND = SWATCH0.BUTTON_FG_ON
          END IF
          IF I = GDATA.TEXT.hi THEN           'HOVER
               DIM AS STRING TMPSTR
               IF I <> GDATA.TEXT.si THEN
                    BACKGROUND = SWATCH0.LIST_BG_HL
                    FOREGROUND = SWATCH0.LIST_FG_HL
               END IF
               TMPSTR = MID(BIN(MODES[I]),TNG_MAXSP-N+1)
               IF LEN(TMPSTR) < N THEN TMPSTR = STRING(N-LEN(TMPSTR),"0")
               TMPSTR = TRIM(MODE_NAMES[I]) & ":  "
               MUTEXLOCK   MT_CTRL_INFO
               Controls[ID]->CTRL_INFO = TMPSTR
               MUTEXUNLOCK MT_CTRL_INFO
          END IF
          LINE DRAWING_DEST, (X,Y)-(X+GDATA.W-BORDER_SIZE-1,Y+LINE_H-1),BACKGROUND,BF

          'TEXT PRINTING
          IF GDATA.TEXT.UPDATED THEN
               DIM AS STRING TMPSTR
               IF (B < Controls[ID]->NB_IMAGES) ANDALSO (Controls[ID]->IMAGE[B] > 0) THEN
                    LINE Controls[ID]->IMAGE[B],(0,0)-(W-1,GDATA.TEXT.FONT_SIZE),0,BF
                    TMPSTR = TRIM(MODE_NAMES[I])
                    R = PrintFT(Controls[ID]->IMAGE[B],GRID_STEP,0,0,TMPSTR,MainFont.Font_hdl,_
                         GDATA.TEXT.FONT_SIZE,FOREGROUND)
               END IF
          END IF
          'DRAW TEXT IMAGE
          IF B < Controls[ID]->NB_IMAGES ANDALSO Controls[ID]->IMAGE[B] > 0 THEN _
               PUT DRAWING_DEST,(X,Y + Y0), Controls[ID]->IMAGE[B], ALPHA
          Y += LINE_H
          B += 1
     NEXT I
 
     GLIST_BOTTOM_CODE()
     
     IF MODE_NAMES > 0 THEN DELETE[] MODE_NAMES
     IF MODES > 0      THEN DELETE[] MODES
     
     RETURN 0
END FUNCTION
'------------------------------------------------------------------------------------------------------------
' BEATBOARD & KEYBOARD

FUNCTION gctrl_bb_frame       (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     ACETATE_TRANSFER(Controls[ID]->IMAGE[0],GDATA.X+BORDER_SIZE,GDATA.Y+BORDER_SIZE)
     DrawFrame(GDATA,FR_SOLID, BORDER_SIZE, GDATA.CLR)
     RETURN 0
END FUNCTION

FUNCTION gctrl_kb_frame       (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     ACETATE_TRANSFER(Controls[ID]->IMAGE[0],GDATA.X+BORDER_SIZE,GDATA.Y+BORDER_SIZE)
     DrawFrame(GDATA,FR_SOLID, BORDER_SIZE, GDATA.CLR)
     RETURN 0
END FUNCTION

FUNCTION gctrl_bb             (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     STATIC AS I32            I,X,Y,X2,Y2, K,O,R
     STATIC AS IOS            W,H
     DIM    AS TXT            TMPSTR
     STATIC AS SOUNDRA.BOARD  PTR BB
     DIM    AS I32            T = SOUNDRA.TIME_BASE, TEXT_WIDTH
     STATIC AS F32            KT
     
     BB = SOUNDRA.BB[SOUNDRA.BB_NUM]
     W  = GDATA.W
     'MOVE THIS INTO A SUB...
     IF GDATA.text.UPDATED THEN
          DIM AS I32 W2,FS
          PATCH_BG()
          SOUNDRA.BB_KEY_H   = GRID_STEP * 9
          SOUNDRA.NB_KEYS_BB = INT(GDATA.H / SOUNDRA.BB_KEY_H)
          IF SOUNDRA.NB_KEYS_BB > SOUNDRA.NB_POWERS(T).OCTAVE THEN
               SOUNDRA.NB_KEYS_BB = SOUNDRA.NB_POWERS(T).OCTAVE
               SOUNDRA.BB_KEY_H   = INT(GDATA.H / SOUNDRA.NB_KEYS_BB)
          END IF
               'WHY ARE THESE CALCULATIONS IN GFX?
          FOR I = 0 TO SOUNDRA.NB_KEYBOARDS_MAX -1 
               SOUNDRA.BB[I]->K_OFFSET.OCTAVE = INT(.5*(SOUNDRA.NB_POWERS(T).OCTAVE - SOUNDRA.NB_KEYS_BB))
          NEXT I
          'TEXT
          O  = SOUNDRA.NB_POWERS(T).OCTAVE - 1 - BB->K_OFFSET.OCTAVE - SOUNDRA.NB_POWERS(T).KEY
          W2 = W - BORDER_SIZE*2 - 2
          FOR I = 0 TO SOUNDRA.NB_KEYS_BB - 1
               'INDEX TO POWER OF PRIME(T)
               K = O-I
               TMPSTR = STR(PRIME(T)^ABS(K))
               IF K < 0 THEN
                    TMPSTR = "1/" & TMPSTR
               ELSEIF K = 0 THEN
                    TMPSTR &= " x"
               END IF
               'DRAW TEXT
               IMAGEINFO(Controls[ID]->IMAGE[I],,H)
               FS = GDATA.TEXT.font_size
               TEXT_WIDTH = GetTXT_W(TMPSTR,MainFont,FS)
               DO WHILE TEXT_WIDTH > W2 AND FS > 8
                    FS        -= 1
                    TEXT_WIDTH = GetTXT_W(TMPSTR,MainFont,FS)
               LOOP
               X2 = .5*(W - TEXT_WIDTH)
               Y2 = .5*(H - FS) + 1
               LINE Controls[ID]->IMAGE[I],(0,0)-(W-1,H-1),0,BF
               R = PrintFT(Controls[ID]->IMAGE[I],X2,Y2,0,TMPSTR,MainFont.Font_Hdl,FS,GDATA.TEXT.FONT_CLR)
          NEXT I
     END IF
     
     'DRAW BG OFF
     W = GDATA.W
     H = SOUNDRA.BB_KEY_H     
     X = GDATA.X
     Y = GDATA.Y
     FOR I = 0 TO SOUNDRA.NB_KEYS_BB - 1
          BACKGROUND  = GDATA.CLR
          FRAME_COLOR = SWATCH0.FRM_OFF
          LINE DRAWING_DEST,(X,Y)-(X+W-1,Y+H-1),BACKGROUND,BF
          K  = SOUNDRA.NB_KEYS_BB - I - 1 + BB->K_OFFSET.OCTAVE
          KT = K / SOUNDRA.NB_POWERS(T).OCTAVE + 0.16666666666
          FRAME_COLOR = COLOR_TEMPERATURE(KT)
          DrawFrame(GDATA,DRAWING_DEST,FR_LIGHT0,2,FRAME_COLOR,X,Y,W,H)
          Y += H
     NEXT I

     'DRAW BG OR LINES FOR ACTIVE CHANNELS
     O  = BB->K_OFFSET.OCTAVE
     X  = GDATA.X
     FOR I = 0 TO SOUNDRA.NB_GCHANNELS_MAX - 1
          IF BB->GCHANNELS(I).CHAN_ID > -1 THEN
               K = BB->GCHANNELS(I).KEY_POS
               IF BB->GCHANNELS(I).KEY_TYPE = SOUNDRA.KEY_MODES.CONTINUOUS THEN
                    K -= H*O
                    IF K > -1 AND K < GDATA.H THEN
                         Y = GDATA.Y + K*H
                         LINE DRAWING_DEST,(X+BORDER_SIZE,Y+BORDER_SIZE)-_
                                           (X+W-1-BORDER_SIZE,Y+1+BORDER_SIZE),SWATCH0.BUTTON_BG_ON,BF
                    END IF
               ELSE
                    K -= O
                    IF K > -1 AND K < SOUNDRA.NB_KEYS_BB THEN
                         Y = GDATA.Y + K*H
                         K  = SOUNDRA.NB_KEYS_BB - K - 1 + O
                         KT = K / SOUNDRA.NB_POWERS(T).OCTAVE + 0.16666666666
                         FRAME_COLOR = COLOR_TEMPERATURE(KT)
                         LINE DRAWING_DEST,(X+BORDER_SIZE,Y+BORDER_SIZE)-_
                                           (X+W-1-BORDER_SIZE,Y+H-1-BORDER_SIZE),clrlev(FRAME_COLOR,.5),BF
                         DrawFrame(GDATA,DRAWING_DEST,FR_LIGHT1,2,SWATCH0.FRM_ACTIVE,X,Y,W,H)
                    END IF
               END IF
          END IF
     NEXT I
     
     'DRAW FRAME FOR HOVER, BG FOR SELECTED
     X  = GDATA.X
     IF GDATA.TEXT.HI > -1 THEN 
          Y = GDATA.Y + GDATA.TEXT.HI*H
          DrawFrame(GDATA,DRAWING_DEST,FR_LIGHT0,2,SWATCH0.FRM_ACTIVE,X,Y,W,H)
     END IF
     IF GDATA.TEXT.SI > -1 THEN 
          Y = GDATA.Y + GDATA.TEXT.SI*H
          K  = SOUNDRA.NB_KEYS_BB - GDATA.TEXT.SI - 1 + O
          KT = K / SOUNDRA.NB_POWERS(T).OCTAVE + 0.16666666666
          FRAME_COLOR = clrlev(COLOR_TEMPERATURE(KT),.5)
          LINE DRAWING_DEST,(X,Y)-(X+W-1,Y+H-1),FRAME_COLOR,BF
          DrawFrame(GDATA,DRAWING_DEST,FR_LIGHT1,2,SWATCH0.FRM_ACTIVE,X,Y,W,H)
     END IF

     'PRINT TEXT IMAGES
     X = GDATA.X
     Y = GDATA.Y
     FOR I = 0 TO SOUNDRA.NB_KEYS_BB - 1
          ACETATE_TRANSFER(Controls[ID]->IMAGE[I],X,Y)
          Y += H
     NEXT I

     RETURN 0
END FUNCTION

SUB KB_TEXT_UPDATE(BYREF GDATA AS _GDATA, ID AS I32,K AS I32,W AS I32, H AS I32)
     DIM AS I32          I,Y,X2,Y2,TEXT_WIDTH,NB_KEYS,KEY_POS,SUB_FONT_SIZE,O
     DIM AS _TEXTLINE    PTR KEY_NAMES
     DIM AS F32          PTR KEY_ABSS
     DIM AS TXT          TMPSTR

     PATCH_BG()
     MUTEXLOCK   MT_TUNINGS(TUNING_CURRENT)
     NB_KEYS    = TUNINGS(TUNING_CURRENT).NB_KEYS
     KEY_NAMES  = NEW _TEXTLINE[NB_KEYS]
     KEY_ABSS   = NEW F32[NB_KEYS]
     FOR I = 0 TO NB_KEYS - 1
          KEY_NAMES[I] = TUNINGS(TUNING_CURRENT).KEY_NAME(I)
          KEY_ABSS[I]  = TUNINGS(TUNING_CURRENT).KEY_ABS(I)
     NEXT I
     MUTEXUNLOCK MT_TUNINGS(TUNING_CURRENT)
     SUB_FONT_SIZE = .66*GDATA.TEXT.font_size
     Y2 = .5*(H-GDATA.TEXT.font_size) - 2
     FOR I = 0 TO SOUNDRA.NB_KEYS_KB - 1
          'KEY NAME
          KEY_POS    = (I + K) MOD NB_KEYS
          IF KEY_POS < 0 THEN KEY_POS += NB_KEYS
          TMPSTR     = KEY_NAMES[KEY_POS]
          TEXT_WIDTH = GetTXT_W(TMPSTR,MainFont,GDATA.TEXT.font_size)
          X2         = .5*(W - TEXT_WIDTH)
          LINE Controls[ID]->IMAGE[I],(0,0)-(W-1,H-1),0,BF
          PrintFT(Controls[ID]->IMAGE[I],X2,Y2,0,TMPSTR,MainFont.Font_Hdl,GDATA.TEXT.font_size,_
               GDATA.TEXT.FONT_CLR)
          'OCTAVE NUMBER
          IF KEY_POS = 0 THEN
               O = (I+K) \ NB_KEYS
               IF O > SOUNDRA.OCTAVE_MAX THEN O -= SOUNDRA.OCTAVE_MAX - SOUNDRA.OCTAVE_MIN + 1
               Y = Y2 + GDATA.TEXT.font_size + 1
               TMPSTR = STR(O)
               PrintFT(Controls[ID]->IMAGE[I],X2,Y,0,TMPSTR,MainFont.Font_Hdl,SUB_FONT_SIZE,_
               GDATA.TEXT.FONT_CLR)
          END IF
          SOUNDRA.KEY_COLOR[I].H = KEY_ABSS[KEY_POS] - 1
     NEXT I
     IF KEY_NAMES > 0 THEN DELETE[] KEY_NAMES
     IF KEY_ABSS  > 0 THEN DELETE[] KEY_ABSS
END SUB

FUNCTION gctrl_kb             (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM    AS I32            I,KID,HID, X,Y,W,H, K,O,R,N
     DIM AS SOUNDRA.BOARD     PTR KB = SOUNDRA.KB[SOUNDRA.KB_NUM]
     DIM AS RGB_PX            TMP_RGB

     W   = SOUNDRA.KEY_BASE_SIZE
     H   = GDATA.H
     
     IF GDATA.text.UPDATED THEN KB_TEXT_UPDATE(GDATA, ID,KB->K_OFFSET.KEY,W,H)
     
     KID = GDATA.text.si
     HID = GDATA.text.hi
     
     'DRAW BG OFF
     X   = GDATA.X
     Y   = GDATA.Y
     FOR I = 0 TO SOUNDRA.NB_KEYS_KB - 1
          TMP_RGB = HSB2RGB(SOUNDRA.KEY_COLOR[I])
          TMP_RGB.CLR = clrlev(TMP_RGB.CLR,.5)
          BACKGROUND  = GDATA.CLR
          FRAME_COLOR = SWATCH0.BUTTON_FRM_OFF
          LINE DRAWING_DEST,(X,Y)-(X+W-1,Y+H-1),BACKGROUND,BF
          DrawFrame(GDATA,DRAWING_DEST,FR_LIGHT0,2,TMP_RGB.CLR,X,Y,W,H)
          X += W
     NEXT I
     
     'DRAW BG OR LINES FOR ACTIVE CHANNELS
     O  = KB->K_OFFSET.KEY
     Y  = GDATA.Y
     FOR I = 0 TO SOUNDRA.NB_GCHANNELS_MAX - 1
          IF KB->GCHANNELS(I).CHAN_ID > -1 THEN
               K = KB->GCHANNELS(I).KEY_POS
               IF KB->GCHANNELS(I).KEY_TYPE = SOUNDRA.KEY_MODES.CONTINUOUS THEN 'NOT IMPLEMENTED YET
                    K -= W*O
                    IF K > -1 AND K < GDATA.W THEN
                         X = GDATA.X + K*W
                         LINE DRAWING_DEST,(X+BORDER_SIZE,Y+BORDER_SIZE)-_
                                           (X+W-1-BORDER_SIZE,Y+1+BORDER_SIZE),SWATCH0.BUTTON_BG_ON,BF
                    END IF
               ELSE
                    K -= O
                    IF K > -1 AND K < SOUNDRA.NB_KEYS_KB THEN
                         TMP_RGB = HSB2RGB(SOUNDRA.KEY_COLOR[K])
                         X = GDATA.X + K*W
                         LINE DRAWING_DEST,(X+BORDER_SIZE,Y+BORDER_SIZE)-_
                                           (X+W-1-BORDER_SIZE,Y+H-1-BORDER_SIZE),clrlev(TMP_RGB.CLR,.5),BF
                         DrawFrame(GDATA,DRAWING_DEST,FR_LIGHT1,2,SWATCH0.FRM_ACTIVE,X,Y,W,H)
                    END IF
               END IF
          END IF
     NEXT I

     'DRAW BG FOR HOVER, SELECTED
     Y  = GDATA.Y
     IF HID > -1 THEN 
          X = GDATA.X + HID*W
          DrawFrame(GDATA,DRAWING_DEST,FR_LIGHT0,2,SWATCH0.FRM_ACTIVE,X,Y,W,H)
     END IF
     IF KID > -1 THEN 
          TMP_RGB = HSB2RGB(SOUNDRA.KEY_COLOR[KID])
          TMP_RGB.CLR = clrlev(TMP_RGB.CLR,.5)
          X = GDATA.X + KID*W
          LINE DRAWING_DEST,(X,Y)-(X+W-1,Y+H-1),TMP_RGB.CLR,BF
          DrawFrame(GDATA,DRAWING_DEST,FR_LIGHT1,2,SWATCH0.FRM_ACTIVE,X,Y,W,H)
     END IF

     'DRAW TEXT
     X = GDATA.X
     Y = GDATA.Y
     FOR I = 0 TO SOUNDRA.NB_KEYS_KB - 1
          ACETATE_TRANSFER(Controls[ID]->IMAGE[I],X,Y)
          X += W
     NEXT I
     
     RETURN 0
END FUNCTION

SUB DRAW_SPECTRUM(BYREF GDATA AS _GDATA, SOUND_DATA AS F32 PTR, SIZE AS I32)
     STATIC AS I32 I,R,W,W2,H,Y0,X0,LENGTH,CLR,XR_OFFSET
     STATIC AS F32 X_1(2),X(2),Y,YSTEP,SCALING,dB_SCALING=SOUNDRA.SCOPE_dB_SCALING
     IF SIZE <> SOUNDRA.SCOPE_SIZE+SOUNDRA.SCOPE_SIZE THEN EXIT SUB
     'DIMENSIONS
     W  = GDATA.W - BORDER_SIZE-BORDER_SIZE
     H  = GDATA.H - BORDER_SIZE-BORDER_SIZE
     X0 = GDATA.X + BORDER_SIZE
     Y0 = GDATA.Y + GDATA.H - BORDER_SIZE-1
     XR_OFFSET = 0
     IF SETTINGS.MONITORS_CURRENT > 1 THEN
          W  = DESK_W - GDATA.X - BORDER_SIZE
          XR_OFFSET = GDATA.W - W - BORDER_SIZE - BORDER_SIZE
     END IF
     R       = FFT2(SOUND_DATA, SOUNDRA.ScopeSpectrum, 0, SOUNDRA.SCOPE_SIZE, 0)
     'DRAWING
     Y       = Y0
     LENGTH  = .5*SOUNDRA.SCOPE_SIZE
     SCALING = 1 / LENGTH
     YSTEP   = 2*H*SCALING
     W2      = 420
     'FIRST DATA POINT
     X_1(0) = dB(SCALING*SOUNDRA.ScopeSpectrum[0])
     X_1(0) = IIF(X_1(0) > dBmin_audible, 1-dB_SCALING*X_1(0),0)
     X_1(1) = dB(SCALING*SOUNDRA.ScopeSpectrum[SOUNDRA.SCOPE_SIZE])
     X_1(1) = IIF(X_1(1) > dBmin_audible, 1-dB_SCALING*X_1(1),0)
     'DRAW LINES, 2px THICK
     FOR I = 1 TO .5*LENGTH-1
          'LEFT
          X(0) = dB(SCALING*SOUNDRA.ScopeSpectrum[I])
          X(0) = IIF(X(0) > dBmin_audible, 1-dB_SCALING*X(0),0)
          CLR  = COLOR_TEMPERATURE(.75*X(0)+.25)
          X_1(0) *= W2
          LINE (X0+X_1(0),Y+1)-(X0+X(0)*W2,Y),CLR
          LINE (X0+X_1(0)+1,Y+1)-(X0+X(0)*W2+1,Y),CLR
          X_1(0) = X(0)
          'RIGHT
          X(1) = dB(SCALING*SOUNDRA.ScopeSpectrum[I+SOUNDRA.SCOPE_SIZE])
          X(1) = IIF(X(1) > dBmin_audible, 1-dB_SCALING*X(1),0)
          CLR  = COLOR_TEMPERATURE(.75*X(1)+.25)
          X_1(1) *= W2
          LINE (X0-X_1(1)+W+XR_OFFSET,Y+1)-(X0+W+XR_OFFSET-X(1)*W2,Y),CLR
          LINE (X0-X_1(1)+W+XR_OFFSET-1,Y+1)-(X0+W+XR_OFFSET-X(1)*W2-1,Y),CLR
          X_1(1) = X(1)
          Y -= YSTEP
     NEXT I
END SUB

SUB DRAW_RAW_SCOPE(BYREF GDATA AS _GDATA, SOUND_DATA AS F32 PTR, SIZE AS I32)
     STATIC AS I32 I,YL,YR,W,H,R,CX,CY
     STATIC AS F32 S,DX
     'DIMENSIONS
     W = GDATA.W - GRID_STEP-GRID_STEP
     H = GDATA.H - GRID_STEP-GRID_STEP
     IF SETTINGS.MONITORS_CURRENT > 1 THEN W = DESK_W - GDATA.X - BORDER_SIZE
     R  = .5*H
     CX = GDATA.X + GRID_STEP
     CY = GDATA.Y + GDATA.H - GRID_STEP - R
     S  = 2*W / SIZE
     DX = 0
     'DRAWING
     FOR I = 0 TO SIZE-2 STEP 2
          YL = R*SOUND_DATA[I]
          YR = R*SOUND_DATA[I+1]
          PUT (CX+DX,CY-YL),SOUNDRA.SCOPE_SPRITE_R,ADD
          PUT (CX+DX,CY-YR),SOUNDRA.SCOPE_SPRITE_B,ADD
          DX += S
     NEXT I
END SUB

SUB DRAW_P2D_SCOPE(BYREF GDATA AS _GDATA, SOUND_DATA AS F32 PTR, SIZE AS I32)
     STATIC AS I32 I,I2,G,L,RH,RW,CX,CY,W,H
     STATIC AS F32 X0,Y0,SIZE_1
     'DIMENSIONS
     W = GDATA.W - GRID_STEP-GRID_STEP
     H = GDATA.H - GRID_STEP-GRID_STEP
     IF SETTINGS.MONITORS_CURRENT > 1 THEN W = DESK_W - GDATA.X - BORDER_SIZE
     RW = .5*W
     RH = .5*H
     CX = GDATA.X + GRID_STEP + RW
     CY = GDATA.Y + GDATA.H - GRID_STEP - RH
     SIZE_1 = 1/SIZE
     'DRAWING
     FOR I = 0 TO SIZE-2 STEP 2
          X0 = RH*SOUND_DATA[I]
          Y0 = RH*SOUND_DATA[I+1]
          I2 = I*SIZE_1
          G  = 255*I2
          L  = 420*(I2-.8)
          FLOOR(L,0)
          PUT (CX+X0,CY-Y0),SOUNDRA.SCOPE_SPRITE_G,ADD,G
          PUT (CX+X0,CY-Y0),SOUNDRA.SCOPE_SPRITE_L,ADD,L
     NEXT I
END SUB
SUB DRAW_V2D_SCOPE(BYREF GDATA AS _GDATA, SOUND_DATA AS F32 PTR, SIZE AS I32)
     STATIC AS I32  I,CR,CG,CLR,RH,RW,CX,CY,W,H
     STATIC AS F32  DX,DY,X0,X1,Y0,Y1,D,B,S,D_1,SIZE_1,LR2
     STATIC AS V2D  V
     'DIMENSIONS
     W = GDATA.W - GRID_STEP-GRID_STEP
     H = GDATA.H - GRID_STEP-GRID_STEP
     IF SETTINGS.MONITORS_CURRENT > 1 THEN W = DESK_W - GDATA.X - BORDER_SIZE
     RW = .5*W
     RH = .5*H
     CX = GDATA.X + GRID_STEP + RW
     CY = GDATA.Y + GDATA.H - GRID_STEP - RH
     SIZE_1 = 1/SIZE
     LR2 = LOG(4*RH*RH)
     X0 = RH*SOUND_DATA[0]
     Y0 = RH*SOUND_DATA[1]
     B  = 0
     S  = 4*SIZE_1
     'DRAWING
     FOR I = 0 TO SIZE - 2 STEP 2
          'SPACE
          X1  = RH*SOUND_DATA[I]
          Y1  = RH*SOUND_DATA[I+1]
          DX  = X1 - X0
          DY  = Y1 - Y0
          D   = DX*DX+DY*DY
          D_1 = IIF(D=0,0,1/SQR(D))
          'COLOR
          B  += S
          IF B > 1 THEN B = 1
          D   = IIF(D<1,0,255*LOG(D)/LR2)
          CR  = INT(B*(255-D))
          CG  = INT(B*D)
          'THICKNESS LINES
          IF D_1 > 0 THEN
               DX *= 2*D_1
               DY *= 2*D_1
               CLR = RGB(.4*CR,.4*CG,0)
               LINE (CX+X0+DX,CY-Y0+DY)-(CX+X1+DX,CY-Y1+DY), CLR
               LINE (CX+X0-DX,CY-Y0-DY)-(CX+X1-DX,CY-Y1-DY), CLR
               DX *= .75
               DY *= .75
               CLR = RGB(.6*CR,.6*CG,0)
               LINE (CX+X0+DX,CY-Y0+DY)-(CX+X1+DX,CY-Y1+DY), CLR
               LINE (CX+X0-DX,CY-Y0-DY)-(CX+X1-DX,CY-Y1-DY), CLR
               DX *= .66
               DY *= .66
               CLR = RGB(.8*CR,.8*CG,0)
               LINE (CX+X0+DX,CY-Y0+DY)-(CX+X1+DX,CY-Y1+DY), CLR
               LINE (CX+X0-DX,CY-Y0-DY)-(CX+X1-DX,CY-Y1-DY), CLR
               DX *= .5
               DY *= .5
               CLR = RGB(.9*CR,.9*CG,0)
               LINE (CX+X0+DX,CY-Y0+DY)-(CX+X1+DX,CY-Y1+DY), CLR
               LINE (CX+X0-DX,CY-Y0-DY)-(CX+X1-DX,CY-Y1-DY), CLR
          END IF
          'MAIN LINE
          CLR = RGB(CR,CG,0)
          LINE (CX+X0,CY-Y0)-(CX+X1,CY-Y1), CLR
          'SAVE LAST POS
          X0  = X1
          Y0  = Y1
     NEXT I
END SUB

FUNCTION gctrl_scope          (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     STATIC AS F32       PTR PTR_COPY(100)
     STATIC AS I32       CHUNK_SIZE(100),DRIFT = 1,START_POS
     STATIC AS F64       T,DT,DT_CUMUL
     STATIC AS F32       PTR SUB_DATA_PTR

     IF (PLAYING AND SOUNDRA.DRAW_OUTPUT AND (SETTINGS.SCOPE_MODE > SOUNDRA.DRAW_MODES.OFF)) = TRUE THEN
          DIM AS I32     I,J,R, W,W2,H,H2,X0,Y0
          DIM AS I32     NB_PTR,SIZE,OFFSET,NEW_SIZE,TAIL_SIZE
          DIM AS F32 PTR SUB_SCOPEDATA
          'COPY THE DATA POINTERS PASSED BY MAIN
          NB_PTR   = 0
          NEW_SIZE = 0
          MUTEXLOCK   SOUNDRA.MT_SCOPEDATA
          I = SOUNDRA.ScopeData_QWID
          DO UNTIL (SOUNDRA.ScopeDataQ(I) = 0) OR (NEW_SIZE > SOUNDRA.SCOPEDATACUTOFF)
               PTR_COPY(NB_PTR)   = SOUNDRA.ScopeDataQ(I)
               CHUNK_SIZE(NB_PTR) = SOUNDRA.ScopeData_QSize(I) 'STEREO
               NEW_SIZE          += CHUNK_SIZE(NB_PTR)
               SOUNDRA.ScopeDataQ(I)      = 0
               SOUNDRA.ScopeData_QSize(I) = 0
               I -= 1
               IF I < 0 THEN I = SOUNDRA.ScopeData_QLen-1
               NB_PTR += 1
          LOOP
          MUTEXUNLOCK SOUNDRA.MT_SCOPEDATA
          'COPY NEW DATA
          FOR I = NB_PTR-1 TO 0 STEP -1
               FOR J = 0 TO CHUNK_SIZE(I)-1
                    SOUNDRA.SCOPEDATA[J+SOUNDRA.SCOPEDATAPOS] = PTR_COPY(I)[J]
               NEXT J
               SOUNDRA.SCOPEDATAPOS += CHUNK_SIZE(I)
               DELETE[] PTR_COPY(I)
               PTR_COPY(I)   = 0
               CHUNK_SIZE(I) = 0
          NEXT I
          'MOVE DATA LEFT BY {DT}
          DT = 2*INT(ABS(TIMER - T) * SOUNDRA.SR) + DT_CUMUL + DRIFT
          TAIL_SIZE = SOUNDRA.SCOPEDATAPOS - DT
          IF TAIL_SIZE > SOUNDRA.SCOPEDATAMIN THEN
               SUB_SCOPEDATA = @SOUNDRA.SCOPEDATA[DT]
               FOR I = 0 TO TAIL_SIZE-1
                    SOUNDRA.SCOPEDATA[I] = SUB_SCOPEDATA[I]
               NEXT I
               SOUNDRA.SCOPEDATAPOS = TAIL_SIZE
               DT_CUMUL  = 0
          ELSE
               DT_CUMUL += DT
          END IF
          'MOVE DATA LEFT BY {THRESHOLD}
          IF SOUNDRA.SCOPEDATAPOS >= SOUNDRA.SCOPEDATACUTOFF THEN
               SUB_SCOPEDATA = @SOUNDRA.SCOPEDATA[SOUNDRA.SCOPEDATAMIN]
               TAIL_SIZE = SOUNDRA.SCOPEDATAPOS - SOUNDRA.SCOPEDATAMIN
               FOR I = 0 TO TAIL_SIZE-1
                    SOUNDRA.SCOPEDATA[I] = SUB_SCOPEDATA[I]
               NEXT I
               SOUNDRA.SCOPEDATAPOS = TAIL_SIZE
          END IF
          'DRAW
          SIZE = SOUNDRA.SCOPEDATAMIN
          CEIL(SIZE,SOUNDRA.SCOPEDATAPOS)
          SUB_DATA_PTR = @SOUNDRA.SCOPEDATA[START_POS]
          SELECT CASE SETTINGS.SCOPE_MODE
          CASE SOUNDRA.DRAW_MODES.RAW_SCOPE
               DRAW_RAW_SCOPE(GDATA,SUB_DATA_PTR,SIZE)
          CASE SOUNDRA.DRAW_MODES.P2D_SCOPE
               DRAW_P2D_SCOPE(GDATA,SUB_DATA_PTR,SIZE)
          CASE SOUNDRA.DRAW_MODES.V2D_SCOPE
               DRAW_V2D_SCOPE(GDATA,SUB_DATA_PTR,SIZE)
          CASE SOUNDRA.DRAW_MODES.SPECTRUM
               DRAW_SPECTRUM(GDATA,SUB_DATA_PTR,SIZE)
          END SELECT
          T = TIMER
     END IF
     RETURN 0
END FUNCTION

FUNCTION gctrl_synth_plane    (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM AS I32     TEXT_SIZE = DEF_FONT_SIZE
     STATIC AS I32  LINE_MASK = &B0011001100110011
     
     IF SOUNDRA.PATCH_MODE THEN
          DIM AS I32               X,Y, W,H, I,J,R,N,NMAX, W_IN, NB_PORTS, MOD_ID, PMOD_ID, IN_ID, CCLR
          DIM AS SOUNDRA.MODULE    PTR OUT_MOD_PTR'COPY
          DIM AS _CTRL             PTR MOD_CON    'COPY
          DIM AS ANY               PTR PIXELS     'COPY
          DIM AS I32               PTR D          'COLOR INDEX
          DIM AS V2D               PTR VC         'CONNECTOR VECTORS
          DIM AS BOX2D             WINBOX         'WINDOW BOUNDARIES
          
          'DRAG FROM LIST - DRAW A DASHED BOX
          IF Controls[ID]->DRAGGING ANDALSO (GDATA.DATA > 0) THEN
               DIM AS SOUNDRA.MODULE PTR MOD_PTR = CAST(SOUNDRA.MODULE PTR,GDATA.DATA)
               IF MOD_PTR > 0 ANDALSO MOD_PTR->GUI_PTR > 0 THEN
                    W = MOD_PTR->GUI_PTR->W
                    H = MOD_PTR->GUI_PTR->H
                    LINE (GDATA.CX,GDATA.CY)-(GDATA.CX+W-1,GDATA.CY+H-1),WHITE,B,&B010101010101010101
               END IF
          END IF
          
          'MODULES CONNECTORS
          WINBOX.L = BORDER_SIZE
          WINBOX.R = GDATA.W - BORDER_SIZE - 1
          WINBOX.T = BORDER_SIZE
          WINBOX.B = GDATA.H - BORDER_SIZE - 1
          NMAX     = SOUNDRA.LI_MODULES.LENGTH*SOUNDRA.NB_PORTS_MAX+1
          VC       = NEW V2D[NMAX]
          D        = NEW I32[NMAX]
          MUTEXLOCK   SOUNDRA.LI_MODULES.MUTEX
          FOR I = 0 TO SOUNDRA.LI_MODULES.LENGTH-1
               'DATA FETCH AND PROCESS
               MOD_CON  = SOUNDRA.MODULES[I]->GUI_PTR
               NB_PORTS = SOUNDRA.MODULES[I]->NB_PORTS
               IF (SOUNDRA.MODULES[I]->FLAGS(SOUNDRA.MF_SHOW)) AND (MOD_CON > 0) THEN
                    W_IN  = MOD_CON->W - BORDER_SIZE - BORDER_SIZE
                    W_IN /= NB_PORTS
                    X     = MOD_CON->X
                    Y     = MOD_CON->Y
                    'CREATE CONNECTORS (FROM INPUTS)
                    FOR J = 0 TO NB_PORTS-1
                         OUT_MOD_PTR = SOUNDRA.MODULES[I]->PORT(J)
                         IF (OUT_MOD_PTR > 0)                                     ANDALSO _
                            (OUT_MOD_PTR->PORT_TYPE = SOUNDRA.PORT_TYPES.DEFAULT) ANDALSO _
                            (OUT_MOD_PTR <> SOUNDRA.MODULES[I])                   ANDALSO _
                            (OUT_MOD_PTR->GUI_PTR > 0) THEN
                              VC[N].X    = OUT_MOD_PTR->GUI_PTR->X + .5*OUT_MOD_PTR->GUI_PTR->W
                              VC[N].Y    = OUT_MOD_PTR->GUI_PTR->Y + OUT_MOD_PTR->GUI_PTR->H - 1
                              VC[N].HEAD = TYPE<P2D>(X+.5*W_IN+1,Y)
                              VC[N]      = ConstrainVector(VC[N], Windows[W_SYNTH])
                              D[N]       = SOUNDRA.MODULES[I]->PARAM(J).DOMAIN
                              IF VC[N].ISNULL = FALSE  THEN N += 1
                         END IF
                         X += W_IN
                    NEXT J
               END IF
          NEXT I
          'OUTPUT CONNECTOR (TO ROOT MODULE)
          OUT_MOD_PTR = SOUNDRA.ROOT_MODULE
          IF (OUT_MOD_PTR > 0) ANDALSO (OUT_MOD_PTR->GUI_PTR > 0) THEN
               VC[N].X = OUT_MOD_PTR->GUI_PTR->X + .5*OUT_MOD_PTR->GUI_PTR->W
               VC[N].Y = OUT_MOD_PTR->GUI_PTR->Y + OUT_MOD_PTR->GUI_PTR->H - 1
               X       = Controls[ControlAccess[CS_SYNTH_OUT]]->X + _
                         .5*Controls[ControlAccess[CS_SYNTH_OUT]]->W
               Y       = Controls[ControlAccess[CS_SYNTH_OUT]]->Y
               VC[N].HEAD = TYPE<P2D>(X,Y)
               VC[N]   = ConstrainVector(VC[N], Windows[W_SYNTH])
               D[N]    = 2
               IF VC[N].ISNULL = FALSE THEN N += 1
          END IF
          MUTEXUNLOCK   SOUNDRA.LI_MODULES.MUTEX
          
          'DRAW CONNECTORS
          SOUNDRA.MOVING_CONNECTORS OR= SETTINGS.GPU_ECO
          IF     SOUNDRA.MOVING_CONNECTORS = TRUE THEN
               FOR I = 0 TO N-1
                    LINE (VC[I].X,VC[I].Y)-(VC[I].X+VC[I].dX,VC[I].Y+VC[I].dY),_
                          SOUNDRA.CONNECT_COLOR(D[I]),,LINE_MASK
               NEXT I
          ELSEIF SOUNDRA.REDRAW_CONNECTORS = TRUE THEN
               SOUNDRA.REDRAW_CONNECTORS = FALSE
               DIM AS IOS IMGW,IMGH,PITCH,BPP
               DIM AS V2D VC_COPY
               IMAGEINFO(Controls[ID]->IMAGE[0],IMGW,IMGH,BPP,PITCH,PIXELS)
               LINE Controls[ID]->IMAGE[0],(0,0)-(IMGW-1,IMGH-1),0,BF
               PITCH /= BPP
               FOR I = 0 TO N-1
                    VC_COPY = VC[I]
                    VC_COPY.X -= GDATA.X
                    VC_COPY.Y -= GDATA.Y
                    SMOOTHLINE(PIXELS,PITCH,VC_COPY,WINBOX,CONNECTOR_SWATCH(D[I]),GRID_STEP+GRID_STEP)
               NEXT I
          END IF
          IF SOUNDRA.MOVING_CONNECTORS = FALSE THEN PUT (GDATA.X,GDATA.Y),Controls[ID]->IMAGE[0],ALPHA
          'ENDINGS
          FOR I = 0 TO N-1
               PUT (VC[I].X-CE_CENTER,VC[I].Y-CE_CENTER),CONNECTOR_ENDING(D[I]),ALPHA
               PUT (VC[I].X+VC[I].dX-CE_CENTER,VC[I].Y+VC[I].dY-CE_CENTER),CONNECTOR_ENDING(D[I]),ALPHA
          NEXT I
          IF VC > 0 THEN DELETE[] VC
          IF D  > 0 THEN DELETE[] D
     END IF
     DrawFrame(GDATA,FR_SOLID, BORDER_SIZE, SWATCH0.FRM_OFF)
     RETURN 0
END FUNCTION

FUNCTION gctrl_module_group  (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM AS I32 R
     DIM AS IOS X,Y,W,H
     FRAME_STYLE = FR_SOLID
     IF GDATA.TEXT.UPDATED THEN
          'BACKGROUND
          IMAGEINFO(CONTROLS[ID]->IMAGE[0],W,H)
          LINE Controls[ID]->IMAGE[0],(0,0)-(W-1,H-1),RGBA(0,0,0,0),BF
          'TEXT SIZE
          GDATA.TEXT.TEXT_WIDTH = GetTXT_W(GDATA.TEXT.CONTENT,MainFont,GDATA.TEXT.FONT_SIZE)
          CEIL(GDATA.TEXT.TEXT_WIDTH,W)
          Controls[ID]->text.text_width = GDATA.TEXT.TEXT_WIDTH '!!!
          'ALIGNMENT
          X = .5*(W - GDATA.TEXT.TEXT_WIDTH)
          Y = .5*(H - GDATA.TEXT.FONT_SIZE)
          R = PrintFT(CONTROLS[ID]->IMAGE[0],X,Y,0,GDATA.TEXT.CONTENT,MainFont.Font_hdl,_
              GDATA.TEXT.FONT_SIZE,GDATA.TEXT.FONT_CLR,GLYPH_ALPHA)
     END IF

     IF SOUNDRA.PATCH_MODE THEN
          'ICONS
          DIM AS ANY PTR MOD_PTR0 = GDATA.DATA
          DIM AS I32 DY,FRAME_OFFSETY, SEL_CLR = WHITE
          DIM AS IOS HLVH
          IF DRAWING_DEST = 0 THEN
               PUT DRAWING_DEST,(GDATA.X,GDATA.Y),Controls[ID]->IMAGE[4],ALPHA
          ELSE
               PUT DRAWING_DEST,(GDATA.X,GDATA.Y),Controls[ID]->IMAGE[4],PSET
          END IF
          IF MOD_PTR0 > 0 THEN
               DIM AS SOUNDRA.MODULE PTR MOD_PTR = CAST(SOUNDRA.MODULE PTR, MOD_PTR0)
               DIM AS SOUNDRA.MODULE PTR SEL_PTR = SOUNDRA.SELECTED_MODULE
               DIM AS I32 SM = 1+MOD_PTR->NBSC '2|3
               IF MOD_PTR->FLAGS(SOUNDRA.MF_VOICE_MODE) THEN
                    X = GDATA.X + BORDER_SIZE + GRID_STEP
                    Y = GDATA.Y + GDATA.H - BORDER_SIZE - GRID_STEP*5
                    ACETATE_TRANSFER(Controls[ID]->IMAGE[1],X,Y)
               END IF
               X = GDATA.X + BORDER_SIZE - 3
               Y = GDATA.Y + GDATA.H - BORDER_SIZE - GRID_STEP*5
               IF SM = 3 ANDALSO SM < Controls[ID]->NB_IMAGES THEN
                    ACETATE_TRANSFER(Controls[ID]->IMAGE[SM],X,Y)
               END IF
               IF MOD_PTR->NB_PORTS = 0 THEN 
                    DY = 3
               ELSE
                    FRAME_OFFSETY = 6*GRID_STEP
               END IF
               #IFDEF DEVMODE
               'IF MOD_PTR->VOICE_MODE THEN
                    DIM AS I32 I
                    H = GDATA.H
                    X = GDATA.X + GDATA.W
                    Y = GDATA.Y + H - 1
                    FOR I = 0 TO MOD_PTR->NBVC-1
                         SM = 2*MOD_PTR->VMAP[I]
                         LINE (X,Y-SM)-(X+10,Y-SM),YELLOW,B
                    NEXT I
               'END IF
               #ENDIF
               IF (SEL_PTR > 0) ANDALSO (SEL_PTR <> MOD_PTR) THEN
                    HLVH = (SEL_PTR->VHOST = MOD_PTR)
                    IF (SEL_PTR->NB_PORTS > 0) ANDALSO _
                       (SEL_PTR->PORT(SEL_PTR->VHOST_PID)->VHOST = MOD_PTR) THEN HLVH = TRUE
               END IF
          END IF
          'FRAME
          X = GDATA.X
          Y = GDATA.Y
          IF     GDATA.state.ACTIVE OR GDATA.state.POWER THEN
               LINE DRAWING_DEST,(X,Y)-(X+GDATA.W-1,Y+GDATA.H-1),BLACK,B
               LINE DRAWING_DEST,(X,Y)-(X+GDATA.W-1,Y+GDATA.H-1),WHITE,B,&b0011001100110011
               LINE DRAWING_DEST,(X+1,Y+1)-(X+GDATA.W-2,Y+GDATA.H-2),WHITE,B,&b0011001100110011
          ELSEIF HLVH = TRUE THEN
               DIM AS I32 C = SOUNDRA.MODULE_COLOR(SOUNDRA.MOD_CATS.KEYS)
               LINE DRAWING_DEST,(X,Y)-(X+GDATA.W-1,Y+GDATA.H-1),BLACK,B
               LINE DRAWING_DEST,(X,Y)-(X+GDATA.W-1,Y+GDATA.H-1),C,B,&b0011001100110011
               LINE DRAWING_DEST,(X+1,Y+1)-(X+GDATA.W-2,Y+GDATA.H-2),C,B,&b0011001100110011
          ELSE 
               DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, SWATCH0.LIST_FRM_OFF)
          END IF
          'COLORED BOX
          LINE DRAWING_DEST,(X+BORDER_SIZE,Y+BORDER_SIZE+FRAME_OFFSETY)-_
                            (X+GDATA.W-BORDER_SIZE-1,Y+GDATA.H-BORDER_SIZE-1),GDATA.CLR,B
          'CENTERED LABEL
          X += BORDER_SIZE
          Y += .5*(GDATA.H + GDATA.TEXT.tm - GRID_STEP*4) + DY + BORDER_SIZE
          ACETATE_TRANSFER(Controls[ID]->IMAGE[0],X,Y)
     ELSE
          DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, SWATCH0.WINDOW_BG)
     END IF
     IF R < 0 THEN RETURN R
     RETURN 0
END FUNCTION

FUNCTION gctrl_module_patch  (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     'FUNCTION CALLED FOR MODULE INPUT AND OUTPUT BUTTONS
     DIM AS IOS CLIPPING, INACTIVE, OUT_CONNECTED, ISVSOURCE
     DIM AS ANY PTR MOD_PTR0 = GDATA.DATA
     FRAME_COLOR = SWATCH0.BUTTON_FRM_OFF
     FRAME_STYLE = FR_SOLID
     IF GDATA.state.HOVER THEN FRAME_COLOR = SWATCH0.FRM_ACTIVE
     
     'CLIPPING|MIDI INDICATION
     IF MOD_PTR0 > 0 THEN
          DIM AS SOUNDRA.MODULE PTR MOD_PTR = CAST(SOUNDRA.MODULE PTR, MOD_PTR0)
          IF     Controls[ID]->label = "MODOUT" THEN
               IF MOD_PTR->SYS_FLAGS(SOUNDRA.MSF_CLIPPING) = TRUE THEN
                    MOD_PTR->SYS_FLAGS(SOUNDRA.MSF_CLIPPING) = FALSE
                    FRAME_COLOR = RED
               END IF
               INACTIVE      = MOD_PTR->INACTIVE
               OUT_CONNECTED = (MOD_PTR->NB_OUTPUTS > 0) OR (MOD_PTR = SOUNDRA.ROOT_MODULE)
          ELSEIF Controls[ID]->label = "MODIN" THEN
               DIM AS I32 INDEX = Controls[ID]->INDEX
               IF MOD_PTR->PARAM(INDEX).ACTIVE = TRUE THEN
                    MOD_PTR->PARAM(INDEX).ACTIVE = FALSE
                    FRAME_COLOR = ORANGE
               END IF
               ISVSOURCE = (MOD_PTR->VHOST_PID = INDEX) 'FOR SELECTION
               'FOR BG COLOR
               IF MOD_PTR->NB_OUTPUTS > 0 ANDALSO MOD_PTR->PARAM(INDEX).FEEDBACK = TRUE THEN
                    GDATA.STATE.POWER_LEVEL = SOUNDRA.INPUT_TYPES.FEEDBACK
               ELSE
                    GDATA.STATE.POWER_LEVEL = MOD_PTR->PARAM(INDEX).INPUT_TYPE
               END IF
          END IF
     END IF
     
     IF    GDATA.state.ACTIVE OR GDATA.STATE.POWER  THEN
          FRAME_STYLE = FR_LIGHT1
          BACKGROUND  = SWATCH0.BUTTON_BG_ACTIVE
          FOREGROUND  = SWATCH0.BUTTON_FG_ACTIVE
     ELSE
          FRAME_STYLE = FR_LIGHT0
          FOREGROUND  = WHITE
          IF     GDATA.state.POWER_LEVEL = SOUNDRA.INPUT_TYPES.EXTERNAL THEN
               BACKGROUND = RGB(0,100,0)
          ELSEIF GDATA.state.POWER_LEVEL = SOUNDRA.INPUT_TYPES.FEEDBACK THEN
               BACKGROUND = RGB(170, 0, 222)   
          ELSEIF GDATA.state.POWER_LEVEL = SOUNDRA.INPUT_TYPES.GLOBAL   THEN
               BACKGROUND = RGB(200, 70, 100)
          ELSE                            'SOUNDRA.INPUT_TYPES.LOCAL
               BACKGROUND = SWATCH0.BUTTON_BG
               FOREGROUND = SWATCH0.BUTTON_FG
               IF INACTIVE = TRUE THEN 
                    BACKGROUND = RGB(100,0,0)
               ELSEIF OUT_CONNECTED = TRUE THEN
                    BACKGROUND = RGB(0,100,0)
               END IF
          END IF
     END IF
     
     PATCH_BG()
     ACETATE_TRANSFER(Controls[ID]->IMAGE[0],GDATA.X + BORDER_SIZE,GDATA.Y + BORDER_SIZE)
     DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, FRAME_COLOR)
     
     RETURN 0
END FUNCTION 

FUNCTION gctrl_synth_output   (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     DIM    AS I32 X,Y
     FRAME_COLOR = SWATCH0.FRM_OFF
     IF    GDATA.state.HOVER    THEN FRAME_COLOR = SWATCH0.FRM_ON
     IF    GDATA.state.ACTIVE   THEN
          FRAME_STYLE = FR_LIGHT1
          BACKGROUND  = SWATCH0.BUTTON_BG_ACTIVE
          FOREGROUND  = SWATCH0.BUTTON_FG_ACTIVE
     ELSEIF GDATA.STATE.POWER THEN
          FRAME_STYLE = FR_LIGHT0
          BACKGROUND  = SWATCH0.BUTTON_BG_ON
          FOREGROUND  = SWATCH0.BUTTON_FG_ON
     ELSE
          FRAME_STYLE = FR_SOLID
          BACKGROUND  = SWATCH0.BUTTON_BG
          FOREGROUND  = SWATCH0.BUTTON_FG
     END IF
     PATCH_BG()
     X = GDATA.X + BORDER_SIZE
     Y = GDATA.Y - GRID_STEP * 2
     ACETATE_TRANSFER(Controls[ID]->IMAGE[0],X,Y)
     Y += GRID_STEP * 4
     ACETATE_TRANSFER(Controls[ID]->IMAGE[1],X,Y)
     DrawFrame(GDATA,FRAME_STYLE, BORDER_SIZE, FRAME_COLOR)
     RETURN 0
END FUNCTION 
SUB SetupPowerDisplay(S AS I32)
     DIM AS I32 I
     IF SOUNDRA.PowerDisplay > 0 THEN DELETE[] SOUNDRA.PowerDisplay
     SOUNDRA.PowerDisplay     = 0
     SOUNDRA.PowerDisplayPos  = 0
     SOUNDRA.PowerDisplay     = NEW F32[S+1]
     SOUNDRA.PowerDisplaySize = S
     FOR I = 0 TO S-7 STEP 6
          SOUNDRA.PowerDisplay[I+2] = dBmin32
          SOUNDRA.PowerDisplay[I+5] = dBmin32
     NEXT I
END SUB
FUNCTION gctrl_pp_display   (BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     STATIC AS I32 I,J,K,X,Y,S,HalfW,HalfH,P0,P1,PLVL
     STATIC AS F32 P(6)
     'COLORS
     STYLE_FLAT_FRAME(SWATCH0.FRM_OFF)
     BACKGROUND = 0
     PATCH_BG()
     'MANAGE BUFFER
     S = 3*(GDATA.W-BORDER_SIZE-BORDER_SIZE)
     IF S = 0 THEN RETURN 0
     IF SOUNDRA.PowerDisplay = 0 ORELSE SOUNDRA.PowerDisplaySize <> S THEN SetupPowerDisplay(S)
     'GET NEW DATA from queue
     MUTEXLOCK   SOUNDRA.MT_SCOPEDATA
     J = SOUNDRA.PowerDisplay_QPos - 6*SOUNDRA.PowerDisplay_QCount
     IF J < 0 THEN J += SOUNDRA.PowerDisplay_QSize
     FOR I = 0 TO SOUNDRA.PowerDisplay_QCount-1
          SOUNDRA.PowerDisplay[SOUNDRA.PowerDisplayPos]   = SOUNDRA.PowerDisplayQ[J]
          SOUNDRA.PowerDisplay[SOUNDRA.PowerDisplayPos+1] = SOUNDRA.PowerDisplayQ[J+1]
          SOUNDRA.PowerDisplay[SOUNDRA.PowerDisplayPos+2] = SOUNDRA.PowerDisplayQ[J+2]
          SOUNDRA.PowerDisplay[SOUNDRA.PowerDisplayPos+3] = SOUNDRA.PowerDisplayQ[J+3]
          SOUNDRA.PowerDisplay[SOUNDRA.PowerDisplayPos+4] = SOUNDRA.PowerDisplayQ[J+4]
          SOUNDRA.PowerDisplay[SOUNDRA.PowerDisplayPos+5] = SOUNDRA.PowerDisplayQ[J+5]
          J += 6
          IF J >= SOUNDRA.PowerDisplay_QSize THEN J = 0
          SOUNDRA.PowerDisplayPos += 6
          IF SOUNDRA.PowerDisplayPos >= SOUNDRA.PowerDisplaySize THEN SOUNDRA.PowerDisplayPos = 0
     NEXT I
     SOUNDRA.PowerDisplay_QCount = 0
     MUTEXUNLOCK SOUNDRA.MT_SCOPEDATA
     'DRAW DATA
     HalfW  = .5*GDATA.W
     HalfH  = .5*GDATA.H
     Y      = GDATA.Y + HalfH
     X      = GDATA.X + HalfW
     HalfH -= BORDER_SIZE
     P0     = 0
     P1     = SOUNDRA.PowerDisplayPos
     K      = SOUNDRA.PowerDisplayPos/6
     FOR I = P0 TO P1-7 STEP 6
          P(0) = SOUNDRA.PowerDisplay[I]  *HalfH        'MIN
          P(1) = SOUNDRA.PowerDisplay[I+1]*HalfH        'MAX
          P(2) = SOUNDRA.PowerDisplay[I+2]              'POWER
          P(3) = SOUNDRA.PowerDisplay[I+3]*HalfH
          P(4) = SOUNDRA.PowerDisplay[I+4]*HalfH
          P(5) = SOUNDRA.PowerDisplay[I+5]
          P(2) = (-dBmin32 + P(2)) / -dBmin32 '[0..1]
          P(2) = P(2) * HalfH
          P(5) = (-dBmin32 + P(5)) / -dBmin32 '[0..1]
          P(5) = P(5) * HalfH
          LINE DRAWING_DEST, (X-K,Y-P(2))-(X-K,Y+P(2)),RGB(100,0,0)
          LINE DRAWING_DEST, (X-K,Y-P(0))-(X-K,Y-P(1)),RGB(255,0,0)
          LINE DRAWING_DEST, (X+K,Y-P(5))-(X+K,Y+P(5)),RGB(0,0,100)
          LINE DRAWING_DEST, (X+K,Y-P(3))-(X+K,Y-P(4)),RGB(0,0,255)
          K -= 1
     NEXT I
     P0 = SOUNDRA.PowerDisplayPos
     P1 = SOUNDRA.PowerDisplaySize
     K  = SOUNDRA.PowerDisplaySize/6 - 1
     FOR I = P0 TO P1-7 STEP 6
          P(0) = SOUNDRA.PowerDisplay[I]  *HalfH        'MIN
          P(1) = SOUNDRA.PowerDisplay[I+1]*HalfH        'MAX
          P(2) = SOUNDRA.PowerDisplay[I+2]              'POWER
          P(3) = SOUNDRA.PowerDisplay[I+3]*HalfH
          P(4) = SOUNDRA.PowerDisplay[I+4]*HalfH
          P(5) = SOUNDRA.PowerDisplay[I+5]
          P(2) = (-dBmin32 + P(2)) / -dBmin32 '[0..1]
          P(2) = P(2) * HalfH
          P(5) = (-dBmin32 + P(5)) / -dBmin32 '[0..1]
          P(5) = P(5) * HalfH
          LINE DRAWING_DEST, (X-K,Y-P(2))-(X-K,Y+P(2)),RGB(100,0,0)
          LINE DRAWING_DEST, (X-K,Y-P(0))-(X-K,Y-P(1)),RGB(255,0,0)
          LINE DRAWING_DEST, (X+K,Y-P(5))-(X+K,Y+P(5)),RGB(0,0,100)
          LINE DRAWING_DEST, (X+K,Y-P(3))-(X+K,Y-P(4)),RGB(0,0,255)
          K -= 1
     NEXT I
     LINE DRAWING_DEST, (X,Y+HALFH)-(X,Y-HALFH),SWATCH0.FRM_OFF 'MIDDLE SEPARATOR
     DrawFrame(GDATA,FR_SOLID, BORDER_SIZE, SWATCH0.FRM_OFF)
     RETURN 0
END FUNCTION 

FUNCTION gctrl_midiin_display(BYREF GDATA AS _GDATA, ID AS I32)    AS I32
     IF (Controls[ID]->NB_IMAGES > 0) ANDALSO (Controls[ID]->IMAGE[0] > 0) THEN
          'TEXT UPDATE
          IF SETTINGS.DISPLAY_MIDIIN = TRUE THEN
               DIM AS IOS               X,Y,W,H,UPDATED
               DIM AS MIDI_MESSAGE      MM
               DIM AS SOUNDRA.MIDI_CONTROL_MAP  PTR MAP_PTR
               MUTEXLOCK   SOUNDRA.MT_MIDISTR
               UPDATED = SOUNDRA.MIDIIN_DISPLAY.UPDATED
               MM      = SOUNDRA.MIDIIN_DISPLAY.MM
               'MAP_PTR = SOUNDRA.MIDIIN_DISPLAY.MAP_PTR
               SOUNDRA.MIDIIN_DISPLAY.UPDATED = FALSE
               MUTEXUNLOCK SOUNDRA.MT_MIDISTR
               IF UPDATED = TRUE THEN
                    DIM AS TXT TMPSTR
                    TMPSTR = "Dev." & STR(MM.INSTANCE) & "  Ch." & STR(MM.CODE1) & " Code " & _
                              STR(MM.CODE0) & " {" & STR(MM.PARAM0) & "," & STR(MM.PARAM1) & "}"
                    'TEXT ALIGNMENT
                    GDATA.TEXT.TEXT_WIDTH = GetTXT_W(TMPSTR,MainFont,GDATA.TEXT.FONT_SIZE)
                    IMAGEINFO(Controls[ID]->IMAGE[0],W,H)
                    CEIL(GDATA.TEXT.TEXT_WIDTH,W)
                    Controls[ID]->text.text_width = GDATA.TEXT.TEXT_WIDTH '!!!
                    X = .5*(W - GDATA.TEXT.TEXT_WIDTH)
                    Y = .5*(H - GDATA.text.font_size)
                    'PATCH BG AND PRINT TEXT
                    LINE Controls[ID]->IMAGE[0],(0,0)-(W-1,H-1),0,BF
                    PrintFT(Controls[ID]->IMAGE[0],X,Y,0,TMPSTR,MainFont.Font_hdl,_
                              GDATA.TEXT.FONT_SIZE,GDATA.TEXT.FONT_CLR)
               END IF
               X = GDATA.X + BORDER_SIZE
               Y = GDATA.Y + BORDER_SIZE
               ACETATE_TRANSFER(Controls[ID]->IMAGE[0],X,Y)
          END IF
     END IF
     RETURN 0
END FUNCTION 