unit AdT2ext4;
{$IFNDEF __TMT__}
{$PACKRECORDS 1}
{$ENDIF}
interface

const
  _arp_vib_loader: Boolean = FALSE;
  _arp_vib_mode: Boolean = FALSE;
  _macro_editor__pos: array[Boolean] of Byte = (1,8);
  _macro_editor__fmreg_hpos: array[Boolean] of Byte = (1,1);
  _macro_editor__fmreg_page: array[Boolean] of Byte = (1,1);
  _macro_editor__fmreg_left_margin: array[Boolean] of Byte = (1,1);
  _macro_editor__fmreg_cursor_pos: array[Boolean] of Byte = (1,1);
  _macro_editor__arpeggio_page: array[Boolean] of Byte = (1,1);
  _macro_editor__vibrato_hpos: array[Boolean] of Byte = (1,1);
  _macro_editor__vibrato_page: array[Boolean] of Byte = (1,1);

const
  arpvib_arpeggio_table: Byte = 1;
  arpvib_vibrato_table:  Byte = 1;

procedure MACRO_EDITOR(instr: Byte; arp_vib_mode: Boolean);
procedure MACRO_BROWSER(instrBrowser: Boolean; updateCurInstr: Boolean);

implementation

uses
{$IFDEF __TMT__}
  CRT,
{$ELSE}
  DOS,
{$ENDIF}
  AdT2opl3,AdT2sys,AdT2keyb,AdT2unit,AdT2extn,AdT2ext2,AdT2ext3,AdT2ext5,AdT2text,AdT2apak,
  StringIO,DialogIO,ParserIO,DepackIO,TxtScrIO;

const
  _pip_xloc: Byte = 1;
  _pip_yloc: Byte = 1;
  _pip_dest: tSCREEN_MEM_PTR = NIL;
  _pip_loop: Boolean = FALSE;

procedure _preview_indic_proc(state: Byte);
begin
  Case state of
    0: ShowStr(_pip_dest,_pip_xloc,_pip_yloc,
               ' PREViEW ',
               macro_background+macro_text_dis);
    1: ShowStr(_pip_dest,_pip_xloc,_pip_yloc,
               ' PREViEW ',
               macro_background+macro_text);
    2: ShowStr(_pip_dest,_pip_xloc,_pip_yloc,
               ' PREViEW ',
               NOT (macro_background+macro_text));
  end;

  If _pip_loop and (state <> 0) then
    ShowStr(_pip_dest,_pip_xloc,_pip_yloc-1,
            ' LOOP',
            macro_background+macro_text)
  else ShowStr(_pip_dest,_pip_xloc,_pip_yloc-1,
               ' LOOP',
               macro_background+macro_text_dis);
end;

const
  _m_4op_chan: array[1..6] of Byte = (2,4,6,11,13,15);
  _m_perc_sim_chan: array[19..20] of Byte = (18,17);

var
  _m_temp,_m_temp2,_m_temp3,_m_temp5: Byte;
  _m_valid_key,_m_temp4: Boolean;
  _m_chan_handle: array[1..18] of Byte;
  _m_channels: Byte;
  _m_flag_4op_backup: Byte;
  _m_event_table_bak: array[1..20] of tCHUNK;
  _m_freq_table_bak,_m_freqtable2_bak: array[1..20] of Word;
  _m_keyoff_loop_bak: array[1..20] of Boolean;
  _m_channel_flag_backup: array[1..20] of Boolean;
  _m_fmpar_table_backup: array[1..20] of tFM_PARAMETER_TABLE;
  _m_volume_table_backup: array[1..20] of Word;
  _m_pan_lock_backup: array[1..20] of Boolean;
  _m_volume_lock_backup: array[1..20] of Boolean;
  _m_peak_lock_backup: array[1..20] of Boolean;
  _m_panning_table_backup: array[1..20] of Byte;
  _m_status_backup: Record
                      replay_forbidden: Boolean;
                      play_status: tPLAY_STATUS;
                    end;

var
  _bak_arpeggio_table,
  _bak_vibrato_table: Byte;
  _bak_common_flag: Byte;
  _bak_volume_scaling: Boolean;

procedure _macro_preview_init(state,instr2: Byte);
begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:_macro_preview_init';
{$ENDIF}

  Case state of
    0: begin
         songdata.flag_4op := _m_flag_4op_backup;
         Move(_m_fmpar_table_backup,fmpar_table,SizeOf(fmpar_table));
         Move(_m_volume_table_backup,volume_table,SizeOf(volume_table));
         Move(_m_panning_table_backup,panning_table,SizeOf(panning_table));
         songdata.instr_macros[current_inst].arpeggio_table := _bak_arpeggio_table;
         songdata.instr_macros[current_inst].vibrato_table := _bak_vibrato_table;
         songdata.common_flag := _bak_common_flag;
         volume_scaling := _bak_volume_scaling;
         reset_player;

         Move(_m_channel_flag_backup,channel_flag,SizeOf(channel_flag));
         Move(_m_event_table_bak,event_table,SizeOf(event_table));
         Move(_m_pan_lock_backup,pan_lock,SizeOf(pan_lock));
         Move(_m_volume_lock_backup,volume_lock,SizeOf(volume_lock));
         Move(_m_peak_lock_backup,peak_lock,SizeOf(volume_lock));

         really_no_status_refresh := FALSE;
         Move(_m_freq_table_bak,freq_table,SizeOf(freq_table));
         Move(_m_freqtable2_bak,freqtable2,SizeOf(freqtable2));
         Move(_m_keyoff_loop_bak,keyoff_loop,SizeOf(keyoff_loop));
         FillChar(macro_table,SizeOf(macro_table),0);
         replay_forbidden := _m_status_backup.replay_forbidden;
         play_status := _m_status_backup.play_status;
       end;

    1: begin
         _m_status_backup.replay_forbidden := replay_forbidden;
         _m_status_backup.play_status := play_status;
         replay_forbidden := TRUE;
         If (play_status <> isStopped) then play_status := isPaused;
         nul_volume_bars;
         really_no_status_refresh := TRUE;
         reset_player;

         FillChar(_m_chan_handle,SizeOf(_m_chan_handle),0);
         Move(channel_flag,_m_channel_flag_backup,SizeOf(_m_channel_flag_backup));
         Move(event_table,_m_event_table_bak,SizeOf(_m_event_table_bak));
         FillChar(channel_flag,SizeOf(channel_flag),BYTE(TRUE));
         Move(pan_lock,_m_pan_lock_backup,SizeOf(pan_lock));
         Move(volume_lock,_m_volume_lock_backup,SizeOf(volume_lock));
         Move(peak_lock,_m_peak_lock_backup,SizeOf(volume_lock));
         Move(panning_table,_m_panning_table_backup,SizeOf(panning_table));
         FillChar(pan_lock,SizeOf(pan_lock),0);
         FillChar(volume_lock,SizeOf(volume_lock),0);
         FillChar(peak_lock,SizeOf(volume_lock),0);
         _m_flag_4op_backup := songdata.flag_4op;
         If NOT percussion_mode and
            NOT (songdata.flag_4op <> 0) then _m_channels := 18
         else If NOT (songdata.flag_4op <> 0) then _m_channels := 15
              else begin
                     If (instr2 <> BYTE_NULL) then
                       begin
                         songdata.flag_4op := $3f;
                         _m_channels := 6;
                       end
                     else begin
                            songdata.flag_4op := 0;
                            If NOT percussion_mode then _m_channels := 18
                            else _m_channels := 15;
                          end;
                   end;

         _bak_arpeggio_table := songdata.instr_macros[current_inst].arpeggio_table;
         _bak_vibrato_table := songdata.instr_macros[current_inst].vibrato_table;
         _bak_common_flag := songdata.common_flag;
         _bak_volume_scaling := volume_scaling;
         songdata.instr_macros[current_inst].arpeggio_table := ptr_arpeggio_table;
         songdata.instr_macros[current_inst].vibrato_table := ptr_vibrato_table;
         songdata.common_flag := songdata.common_flag AND NOT $80;
         volume_scaling := FALSE;
         reset_player;

         Move(fmpar_table,_m_fmpar_table_backup,SizeOf(_m_fmpar_table_backup));
         Move(volume_table,_m_volume_table_backup,SizeOf(_m_volume_table_backup));
         Move(freq_table,_m_freq_table_bak,SizeOf(freq_table));
         Move(freqtable2,_m_freqtable2_bak,SizeOf(freqtable2));
         Move(keyoff_loop,_m_keyoff_loop_bak,SizeOf(keyoff_loop));
         FillChar(keyoff_loop,SizeOf(keyoff_loop),FALSE);

         misc_register := current_tremolo_depth SHL 7+
                          current_vibrato_depth SHL 6+
                          BYTE(percussion_mode) SHL 5;
         key_off(17);
         key_off(18);
         opl2out(_instr[11],misc_register);

         macro_speedup := songdata.macro_speedup;
         If (play_status = isStopped) then update_timer(songdata.tempo);
       end;
  end;
end;

procedure _macro_preview_body(instr,instr2,chan: Byte; fkey: Word);

function output_note(chan,board_pos: Byte): Boolean;

var
  note: Byte;
  freq: Word;

begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:_macro_preview_body:output_note';
{$ENDIF}

  note := board_pos+12*(current_octave-1);
  If NOT (note in [0..12*8+1]) then
    begin
      output_note := FALSE;
      EXIT;
    end;

  _m_chan_handle[chan] := board_scancodes[board_pos];
  If (songdata.flag_4op <> 0) and (instr2 <> BYTE_NULL) then chan := _m_4op_chan[chan];
  load_instrument(songdata.instr_data[instr],chan);

  If percussion_mode and
     (songdata.instr_data[instr].perc_voice in [4,5]) then
    load_instrument(songdata.instr_data[instr],_m_perc_sim_chan[chan]);

  If (songdata.flag_4op <> 0) and (instr2 <> BYTE_NULL) then
    load_instrument(songdata.instr_data[instr2],PRED(chan));

  freq := nFreq(note-1)+$2000+
          SHORTINT(tDUMMY_BUFF(Addr(songdata.instr_data[instr])^)[12]);

  event_table[chan].note := note;
  opl3out($0b0+_chan_n[chan],0);
  opl3out($0a0+_chan_n[chan],LO(freq));
  opl3out($0b0+_chan_n[chan],HI(freq));

  freq_table[chan] := freq;
  freqtable2[chan] := freq;
  init_macro_table(chan,note,instr,freq);

  If (songdata.flag_4op <> 0) and (instr2 <> BYTE_NULL) then
    begin
      freq_table[PRED(chan)] := freq;
      freqtable2[PRED(chan)] := freq;
      init_macro_table(PRED(chan),note,instr2,freq);
    end;
end;

begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:_macro_preview_body';
{$ENDIF}

  If ctrl_pressed or alt_pressed or shift_pressed then EXIT;
  _m_valid_key := FALSE;
  For _m_temp := 1 to 29 do
    If NOT shift_pressed then
      If (board_scancodes[_m_temp] = HI(fkey)) then
        begin _m_valid_key := TRUE; BREAK; end;

  If NOT _m_valid_key or
     NOT (_m_temp+12*(current_octave-1)-1 in [0..12*8+1]) then EXIT;

  If NOT percussion_mode then _m_channels := 18
  else _m_channels := 15;

  _m_temp2 := _m_temp;
  If percussion_mode and
     (songdata.instr_data[instr].perc_voice in [1..5]) then
    begin
      output_note(songdata.instr_data[instr].perc_voice+15,_m_temp2);
      While scankey(board_scancodes[_m_temp2]) do
        begin
{$IFDEF __TMT__}
          realtime_gfx_poll_proc;
{$ELSE}
          _emulate_screen_without_delay := TRUE;
          keyboard_poll_input;
{$ENDIF}
          keyboard_reset_buffer;
          emulate_screen;
        end;
    end
  else
    begin
      Repeat
        _m_valid_key := FALSE;

        For _m_temp := 1 to 29 do
          begin
            _m_temp2 := board_scancodes[_m_temp];
            _m_temp4 := scankey(_m_temp2);

            If NOT ((songdata.flag_4op <> 0) and (instr2 <> BYTE_NULL)) then
              begin
                _m_temp3 := get_chanpos(_m_chan_handle,_m_channels,_m_temp2);
                _m_temp5 := get_chanpos(_m_chan_handle,_m_channels,0)
              end
            else begin
                   _m_temp3 := get_chanpos2(_m_chan_handle,_m_channels,_m_temp2);
                   _m_temp5 := get_chanpos2(_m_chan_handle,_m_channels,0)
                 end;

            If _m_temp4 then _m_valid_key := TRUE;
            If _m_temp4 and (_m_temp3 = 0) and (_m_temp5 <> 0) then
              output_note(_m_temp5,_m_temp);

            If NOT _m_temp4 and (_m_temp3 <> 0) then
              begin
                key_off(_m_temp3);
                _m_chan_handle[_m_temp3] := 0;
              end;
          end;
{$IFDEF __TMT__}
          realtime_gfx_poll_proc;
{$ELSE}
          _emulate_screen_without_delay := TRUE;
          keyboard_poll_input;
{$ENDIF}
          keyboard_reset_buffer;
          emulate_screen;
      until NOT _m_valid_key;
    end;
end;

procedure MACRO_EDITOR(instr: Byte; arp_vib_mode: Boolean);

const
  EMPTY_FIELD = $0ffff;
  COMMON_FLAG = $08000;

var
  window_area_inc_x: Byte;
  window_area_inc_y: Byte;

procedure fmreg_page_refresh(xpos,ypos: Byte; page: Word); forward;
procedure arpeggio_page_refresh(xpos,ypos: Byte; page: Word); forward;
procedure arpeggio_page_refresh_alt(xpos,ypos: Byte; page: Word); forward;
procedure vibrato_page_refresh(xpos,ypos: Byte; page: Word); forward;
procedure vibrato_page_refresh_alt(xpos,ypos: Byte; page: Word); forward;

procedure _show_proc(show_proc_index: integer; xpos,ypos: Byte; page: Word);
begin
  Case show_proc_index of
    1: fmreg_page_refresh(xpos,ypos,page);
    2: arpeggio_page_refresh(xpos,ypos,page);
    3: arpeggio_page_refresh_alt(xpos,ypos,page);
    4: vibrato_page_refresh(xpos,ypos,page);
    5: vibrato_page_refresh_alt(xpos,ypos,page);
  end;
end;

procedure show_queue(x,y: Byte; page_len: Byte; page,len: Word; show_proc_index: integer);

var
  temp1,temp3: Byte;
  spos,epos: Byte;

begin
  If (PRED(page) < page_len DIV 2) then
    spos := page_len DIV 2-PRED(page)
  else spos := 0;
  If (PRED(page) > len-page_len DIV 2-1) then
    epos := PRED(page)-(len-page_len DIV 2-1)
  else epos := 0;

  If (spos <> 0) or (epos <> 0) then
    begin
      If (spos <> 0) then
        For temp3 := 1 to spos do
          _show_proc(show_proc_index,x,y+temp3,EMPTY_FIELD);

      If (epos <> 0) then
        For temp3 := page_len downto page_len-epos+1 do
          _show_proc(show_proc_index,x,y+temp3,EMPTY_FIELD);

    end;

  For temp1 := 1+spos to page_len-epos do
    If (temp1 <> SUCC(page_len DIV 2)) then
      _show_proc(show_proc_index,x,y+temp1,PRED(page)+temp1-page_len DIV 2)
    else
      _show_proc(show_proc_index,x,y+temp1,PRED(page)+temp1-page_len DIV 2+COMMON_FLAG);
end;

const
  _panning: array[0..2] of Char = 'ñ<>';
  _hex: array[0..15] of Char = '0123456789ABCDEF';

const
  new_keys: array[1..33] of Word = (kF1,kESC,kENTER,kSPACE,kTAB,kShTAB,kUP,kDOWN,
                                    kCtrlO,kF2,kCtrlF2,kF3,kCtrlL,kCtrlS,kCtrlM,
                                    kCtENTR,kAltC,kAltP,kCtrlC,kCtrlV,
                                    kCtPgUP,kCtPgDN,kSPACE,
                                    kCHplus,kNPplus,kCHmins,kNPmins,
                                    kCtLbr,kCtRbr,
                                    kCtHOME,kCtEND,kCtLEFT,kCtRGHT);
var
  old_keys: array[1..33] of Word;
  temps,tstr: String;
  xstart,ystart,temp,temp1: Byte;
  fmreg_cursor_pos,
  fmreg_left_margin: Byte;
  fmreg_hpos: Byte;
  pos,vibrato_hpos: Byte;
  attr: array[1..20] of Byte;
  frame_type: array[1..3] of String;
  fmreg_page,arpeggio_page,
  vibrato_page: Byte;
  fmreg_str: String;
  call_pickup_proc,call_pickup_proc2: Boolean;
  nope: Boolean;
  attr2: array[1..5] of Byte;
  _source_ins,_source_ins2: Byte;
  temp_marks: array[1..255] of Char;

function min0(number: Integer; flag: Integer): Integer;
begin
  If (number > 0) then min0 := number
  else min0 := flag;
end;

function fmreg_def_attr(page: Byte): Word;

var
  attr,
  attr2: Byte;

begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:fmreg_def_attr';
{$ENDIF}

  If (page <= songdata.instr_macros[instr].length) then
    If (page >= songdata.instr_macros[instr].loop_begin) and
       (page <= songdata.instr_macros[instr].loop_begin+
                PRED(songdata.instr_macros[instr].loop_length)) and
       (songdata.instr_macros[instr].loop_begin > 0) and
       (songdata.instr_macros[instr].loop_length > 0) then
      begin
        attr := macro_background+macro_text_loop;
        attr2 := macro_current_bckg+macro_current_loop;
      end
    else If (page >= songdata.instr_macros[instr].keyoff_pos) and
            (songdata.instr_macros[instr].keyoff_pos > 0) then
           begin
             attr := macro_background+macro_text_keyoff;
             attr2 := macro_current_bckg+macro_current_koff;
           end
         else
           begin
             attr := macro_background+macro_text;
             attr2 := macro_current_bckg+macro_current;
           end
  else
    begin
      attr := macro_background+macro_text_dis;
      attr2 := macro_current_bckg+macro_current_dis;
    end;

  fmreg_def_attr := attr+attr2 SHL 8;
end;

function _fmreg_str(page: Byte): String;

var
  fmreg_str: String;

begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:_fmreg_str';
{$ENDIF}

  With songdata.instr_macros[instr].data[page].fm_data do
    begin
      fmreg_str := _hex[ATTCK_DEC_modulator SHR 4]+' '+
                   _hex[ATTCK_DEC_modulator AND $0f]+' '+
                   _hex[SUSTN_REL_modulator SHR 4]+' '+
                   _hex[SUSTN_REL_modulator AND $0f]+' '+
                   _hex[WAVEFORM_modulator AND 7]+' '+
                   byte2hex(KSL_VOLUM_modulator AND $3f)+' '+
                   _hex[KSL_VOLUM_modulator SHR 6]+' '+
                   _hex[AM_VIB_EG_modulator AND $0f]+' ';

      If (AM_VIB_EG_modulator SHR 7 = 0) then fmreg_str := fmreg_str+'ú'
      else fmreg_str := fmreg_str+'T';

      If (AM_VIB_EG_modulator SHR 6 AND 1 = 0) then fmreg_str := fmreg_str+'ú'
      else fmreg_str := fmreg_str+'V';

      If (AM_VIB_EG_modulator SHR 4 AND 1 = 0) then fmreg_str := fmreg_str+'ú'
      else fmreg_str := fmreg_str+'K';

      If (AM_VIB_EG_modulator SHR 5 AND 1 = 0) then fmreg_str := fmreg_str+'ú '
      else fmreg_str := fmreg_str+'S ';

      fmreg_str := fmreg_str+
                   _hex[ATTCK_DEC_carrier SHR 4]+' '+
                   _hex[ATTCK_DEC_carrier AND $0f]+' '+
                   _hex[SUSTN_REL_carrier SHR 4]+' '+
                   _hex[SUSTN_REL_carrier AND $0f]+' '+
                   _hex[WAVEFORM_carrier AND 7]+' '+
                   byte2hex(KSL_VOLUM_carrier AND $3f)+' '+
                   _hex[KSL_VOLUM_carrier SHR 6]+' '+
                   _hex[AM_VIB_EG_carrier AND $0f]+' ';

      If (AM_VIB_EG_carrier SHR 7 = 0) then fmreg_str := fmreg_str+'ú'
      else fmreg_str := fmreg_str+'T';

      If (AM_VIB_EG_carrier SHR 6 AND 1 = 0) then fmreg_str := fmreg_str+'ú'
      else fmreg_str := fmreg_str+'V';

      If (AM_VIB_EG_carrier SHR 4 AND 1 = 0) then fmreg_str := fmreg_str+'ú'
      else fmreg_str := fmreg_str+'K';

      If (AM_VIB_EG_carrier SHR 5 AND 1 = 0) then fmreg_str := fmreg_str+'ú '
      else fmreg_str := fmreg_str+'S ';

      fmreg_str := fmreg_str+_hex[FEEDBACK_FM AND 1]+' ';
      fmreg_str := fmreg_str+_hex[FEEDBACK_FM SHR 1 AND 7]+' ';
    end;

  With songdata.instr_macros[instr].data[page] do
    begin
      If (freq_slide < 0) then fmreg_str := fmreg_str+'-'+ExpStrL(Num2str(Abs(freq_slide),16),3,'0')+' '
      else fmreg_str := fmreg_str+'+'+ExpStrL(Num2str(Abs(freq_slide),16),3,'0')+' ';

      fmreg_str := fmreg_str+
                   _panning[panning]+' '+
                   byte2hex(duration);
    end;

  _fmreg_str := fmreg_str;
end;

function _dis_fmreg_col(fmreg_col: Byte): Boolean;

var
  result: Boolean;

begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:_dis_fmreg_col';
{$ENDIF}

  result := FALSE;
  Case fmreg_col of
    1,2,3,4,
    5: If songdata.dis_fmreg_col[instr][fmreg_col-1] then
         result := TRUE;
    6,
    7: If songdata.dis_fmreg_col[instr][5] then
         result := TRUE;

    8,9,10,11,12,13,
    14,15,16,17,
    18: If songdata.dis_fmreg_col[instr][fmreg_col-2] then
          result := TRUE;
    19,
    20: If songdata.dis_fmreg_col[instr][17] then
          result := TRUE;

    21,22,23,24,
    25,26,27,
    28: If songdata.dis_fmreg_col[instr][fmreg_col-3] then
          result := TRUE;

    29,30,31,
    32: If songdata.dis_fmreg_col[instr][26] then
          result := TRUE;

    33: If songdata.dis_fmreg_col[instr][27] then
          result := TRUE;
  end;

  If (fmreg_col in [14..28]) and
     (songdata.instr_data[current_inst].perc_voice in [2..5]) then
    result := TRUE;

  _dis_fmreg_col := result;
end;

function _str1(def_chr: Char): String;

const
  _on_off: array[BOOLEAN] of Char = (#205,#254);

var
  temp: Byte;
  temp_str: String;

begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:_str1';
{$ENDIF}

  temp_str := '';
  _on_off[FALSE] := def_chr;

  For temp := 0 to 4 do
    temp_str := temp_str+
                _on_off[songdata.dis_fmreg_col[instr][temp]]+def_chr;

  temp_str := temp_str+
              _on_off[songdata.dis_fmreg_col[instr][5]]+
              _on_off[songdata.dis_fmreg_col[instr][5]]+def_chr;

  temp_str := temp_str+
              _on_off[songdata.dis_fmreg_col[instr][6]]+
              def_chr+
              _on_off[songdata.dis_fmreg_col[instr][7]]+def_chr;

  temp_str := temp_str+
              _on_off[songdata.dis_fmreg_col[instr][8]]+
              _on_off[songdata.dis_fmreg_col[instr][9]]+
              _on_off[songdata.dis_fmreg_col[instr][10]]+
              _on_off[songdata.dis_fmreg_col[instr][11]]+def_chr;

  For temp := 12 to 16 do
    temp_str := temp_str+
                _on_off[songdata.dis_fmreg_col[instr][temp]]+def_chr;

  temp_str := temp_str+
              _on_off[songdata.dis_fmreg_col[instr][17]]+
              _on_off[songdata.dis_fmreg_col[instr][17]]+def_chr;

  temp_str := temp_str+
              _on_off[songdata.dis_fmreg_col[instr][18]]+def_chr+
              _on_off[songdata.dis_fmreg_col[instr][19]]+def_chr;

  temp_str := temp_str+
              _on_off[songdata.dis_fmreg_col[instr][20]]+
              _on_off[songdata.dis_fmreg_col[instr][21]]+
              _on_off[songdata.dis_fmreg_col[instr][22]]+
              _on_off[songdata.dis_fmreg_col[instr][23]]+def_chr;

  For temp := 24 to 25 do
    temp_str := temp_str+
                _on_off[songdata.dis_fmreg_col[instr][temp]]+def_chr;

  temp_str := temp_str+
              _on_off[songdata.dis_fmreg_col[instr][26]]+
              _on_off[songdata.dis_fmreg_col[instr][26]]+
              _on_off[songdata.dis_fmreg_col[instr][26]]+
              _on_off[songdata.dis_fmreg_col[instr][26]]+def_chr;

  temp_str := temp_str+
              _on_off[songdata.dis_fmreg_col[instr][27]];

  _str1 := temp_str;
end;

function _str2(str: String; len: Byte): String;
begin
  asm
        lea     esi,[str]
        mov     edi,@RESULT
        movzx   ebx,len
        xor     edx,edx
        push    edi
        lodsb
        inc     edi
        xor     ecx,ecx
        mov     ecx,ebx
        jecxz   @@3
        movzx   ecx,al
        jecxz   @@3
@@1:    cmp     edx,ebx
        jae     @@3
        lodsb
        stosb
        cmp     al,'`'
        jz      @@2
        inc     edx
@@2:    loop    @@1
@@3:    pop     edi
        mov     eax,esi
        lea     esi,[str]
        sub     eax,esi
        dec     eax
        stosb
  end;
end;

procedure fmreg_page_refresh(xpos,ypos: Byte; page: Word);

var
  attr,attr2: Byte;
  temps,fmreg_str2: String;
  fmreg_col,index,
  index2: Byte;
  dummy_str: String;

begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:fmreg_page_refresh';
{$ENDIF}

  attr := LO(fmreg_def_attr(page AND $0fff));
  attr2 := HI(fmreg_def_attr(page AND $0fff));
  fmreg_str := _fmreg_str(page AND $0fff);
  fmreg_str2 := fmreg_str;

  index := 0;
  index2 := 0;

  For fmreg_col := 1 to 35-1 do
    If _dis_fmreg_col(fmreg_col) then
      begin
        Insert('`',fmreg_str2,pos5[fmreg_col]+index);
        Insert('`',fmreg_str2,pos5[fmreg_col]+index+2);
        If (pos5[fmreg_col] < fmreg_left_margin) then Inc(index2,2);
        Inc(index,2);
      end;

  temps := Copy(fmreg_str2,fmreg_left_margin+index2,
                Length(fmreg_str2)-fmreg_left_margin-index2+1);

  If (songdata.instr_macros[instr].data[page AND $0ff].fm_data.
      FEEDBACK_FM OR $80 <> songdata.instr_macros[instr].data[page AND $0ff].fm_data.
                            FEEDBACK_FM) then
    dummy_str := '`'+#$0d+'`'
  else dummy_str := #$0d;

  If NOT arp_vib_mode then
    begin
      If (page <> EMPTY_FIELD) then
        If (page OR COMMON_FLAG <> page) then
          ShowC3Str(ptr_temp_screen,xpos,ypos,
                    '~'+byte2hex(page)+'~ ³~'+dummy_str+'~ö~'+
                    _str2(temps,31+window_area_inc_x)+'~',
                    macro_background+macro_text,
                    attr,
                    macro_background+macro_text_dis)
        else
          ShowC3Str(ptr_temp_screen,xpos-1,ypos,
                    ' ~'+byte2hex(page AND NOT COMMON_FLAG)+'~ ³~'+dummy_str+'~ö~'+
                    _str2(temps,31+window_area_inc_x)+'~ ',
                    macro_current_bckg+macro_current,
                    attr2,
                    macro_current_bckg+macro_current_dis)
      else
        ShowStr(ptr_temp_screen,xpos,ypos,ExpStrL('',36,' '),attr);
    end
  else
    begin
      If (page <> EMPTY_FIELD) then
        If (page OR COMMON_FLAG <> page) then
          ShowC3Str(ptr_temp_screen,xpos,ypos,
                    byte2hex(page)+' ³~'+dummy_str+'~ö~'+
                    _str2(temps,31+window_area_inc_x)+'~',
                    macro_background+macro_text_dis,
                    macro_background+macro_text_dis,
                    macro_background+macro_text_dis)
        else
          ShowC3Str(ptr_temp_screen,xpos-1,ypos,
                    ' '+
                    byte2hex(page AND NOT COMMON_FLAG)+' ³~'+dummy_str+'~ö~'+
                    _str2(temps,31+window_area_inc_x)+'~ ',
                    macro_background+macro_text_dis,
                    macro_background+macro_text_dis,
                    macro_background+macro_text_dis)
      else
        ShowStr(ptr_temp_screen,xpos,ypos,ExpStrL('',36,' '),
                macro_background+macro_text_dis);
    end;
end;

function arpeggio_def_attr(page: Byte): Word;

var
  attr,
  attr2: Byte;

begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:arpeggio_def_attr';
{$ENDIF}

  If (page <= songdata.macro_table[ptr_arpeggio_table].
              arpeggio.length) then
    If (page >= songdata.macro_table[ptr_arpeggio_table].
                arpeggio.loop_begin) and
       (page <= songdata.macro_table[ptr_arpeggio_table].
                arpeggio.loop_begin+
                PRED(songdata.macro_table[ptr_arpeggio_table].
                     arpeggio.loop_length)) and
       (songdata.macro_table[ptr_arpeggio_table].
        arpeggio.loop_begin > 0) and
       (songdata.macro_table[ptr_arpeggio_table].
        arpeggio.loop_length > 0) then
      begin
        attr := macro_background+macro_text_loop;
        attr2 := macro_current_bckg+macro_current_loop;
      end
    else If (page >= songdata.macro_table[ptr_arpeggio_table].
                     arpeggio.keyoff_pos) and
            (songdata.macro_table[ptr_arpeggio_table].
             arpeggio.keyoff_pos > 0) then
           begin
             attr := macro_background+macro_text_keyoff;
             attr2 := macro_current_bckg+macro_current_koff;
           end
         else begin
                attr := macro_background+macro_text;
                attr2 := macro_current_bckg+macro_current;
              end
  else begin
         attr := macro_background+macro_text_dis;
         attr2 := macro_current_bckg+macro_current_dis;
       end;

  arpeggio_def_attr := attr+attr2 SHL 8;
end;

procedure arpeggio_page_refresh(xpos,ypos: Byte; page: Word);

var
  attr,attr2: Byte;
  temps: String;

begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:arpeggio_page_refresh';
{$ENDIF}

  attr  := LO(arpeggio_def_attr(page AND $0fff));
  attr2 := HI(arpeggio_def_attr(page AND $0fff));

  Case songdata.macro_table[ptr_arpeggio_table].
       arpeggio.data[page AND $0fff] of
    0: temps := 'úúú';
    1..96: temps := '+'+ExpStrR(Num2str(songdata.macro_table[ptr_arpeggio_table].
                                        arpeggio.data[page AND $0fff],10),2,' ');
    $80..$80+12*8+1:
       temps := note_layout[songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.data[page AND $0fff]-$80];
  end;

  If (page <> EMPTY_FIELD) then
    If (page OR COMMON_FLAG <> page) then
      ShowCStr(ptr_temp_screen,xpos,ypos,
               '~'+byte2hex(page AND NOT COMMON_FLAG)+'~ ³ ~'+
               temps+'~',
               macro_background+macro_text,attr)
    else
      ShowCStr(ptr_temp_screen,xpos-1,ypos,
               ' ~'+byte2hex(page AND NOT COMMON_FLAG)+'~ ³ ~'+
               temps+'~ ',
               macro_current_bckg+macro_current,attr2)
  else
    ShowStr(ptr_temp_screen,xpos,ypos,ExpStrL('',9,' '),attr);
end;

function vibrato_def_attr(page: Byte): Word;

var
  attr,
  attr2: Byte;

begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:vibrato_def_attr';
{$ENDIF}

  If (page <= songdata.macro_table[ptr_vibrato_table].
              vibrato.length) then
    If (page >= songdata.macro_table[ptr_vibrato_table].
                vibrato.loop_begin) and
       (page <= songdata.macro_table[ptr_vibrato_table].
                vibrato.loop_begin+
                PRED(songdata.macro_table[ptr_vibrato_table].
                     vibrato.loop_length)) and
       (songdata.macro_table[ptr_vibrato_table].
        vibrato.loop_begin > 0) and
       (songdata.macro_table[ptr_vibrato_table].
        vibrato.loop_length > 0) then
      begin
        attr := macro_background+macro_text_loop;
        attr2 := macro_current_bckg+macro_current_loop;
      end
    else If (page >= songdata.macro_table[ptr_vibrato_table].
                     vibrato.keyoff_pos) and
            (songdata.macro_table[ptr_vibrato_table].
             vibrato.keyoff_pos > 0) then
           begin
             attr := macro_background+macro_text_keyoff;
             attr2 := macro_current_bckg+macro_current_koff;
           end
         else begin
                attr := macro_background+macro_text;
                attr2 := macro_current_bckg+macro_current;
              end
  else begin
         attr := macro_background+macro_text_dis;
         attr2 := macro_current_bckg+macro_current_dis;
       end;

  vibrato_def_attr := attr+attr2 SHL 8;
end;

procedure vibrato_page_refresh(xpos,ypos: Byte; page: Word);

var
  attr,attr2: Byte;
  temps: String;

begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:vibrato_page_refresh';
{$ENDIF}

  attr  := LO(vibrato_def_attr(page AND $0fff));
  attr2 := HI(vibrato_def_attr(page AND $0fff));

  If (songdata.macro_table[ptr_vibrato_table].
      vibrato.data[page AND $0fff] = 0) then temps := 'úúú'
  else If (songdata.macro_table[ptr_vibrato_table].
           vibrato.data[page AND $0fff] < 0) then
         temps := '-'+byte2hex(Abs(songdata.macro_table[ptr_vibrato_table].
                                   vibrato.data[page AND $0fff]))
       else
         temps := '+'+byte2hex(Abs(songdata.macro_table[ptr_vibrato_table].
                                   vibrato.data[page AND $0fff]));

  If (page <> EMPTY_FIELD) then
    If (page OR COMMON_FLAG <> page) then
      ShowCStr(ptr_temp_screen,xpos,ypos,
               '~'+byte2hex(page AND NOT COMMON_FLAG)+'~ ³ ~'+
               temps+'~',
               macro_background+macro_text,attr)
    else
      ShowCStr(ptr_temp_screen,xpos-1,ypos,
               ' ~'+byte2hex(page AND NOT COMMON_FLAG)+'~ ³ ~'+
               temps+'~ ',
               macro_current_bckg+macro_current,attr2)
  else
    ShowStr(ptr_temp_screen,xpos,ypos,ExpStrL('',9,' '),attr);
end;

procedure arpeggio_page_refresh_alt(xpos,ypos: Byte; page: Word);
begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:arpeggio_page_refresh_alt';
{$ENDIF}

  If (page <> EMPTY_FIELD) then
    If (page OR COMMON_FLAG <> page) then
      ShowCStr(ptr_temp_screen,xpos,ypos,
               byte2hex(page AND NOT COMMON_FLAG)+' ³ ~'+
               'úúú'+'~',
               macro_background+macro_text_dis,
               macro_background+macro_text_dis)
    else
      ShowCStr(ptr_temp_screen,xpos-1,ypos,
               ' '+
               byte2hex(page AND NOT COMMON_FLAG)+' ³ ~'+
               'úúú'+'~ ',
               macro_background+macro_text_dis,
               macro_background+macro_text_dis)
  else
    ShowStr(ptr_temp_screen,xpos,ypos,
            ExpStrL('',9,' '),
            macro_background+macro_text_dis);
end;

procedure vibrato_page_refresh_alt(xpos,ypos: Byte; page: Word);
begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:vibrato_page_refresh_alt';
{$ENDIF}

  temps := 'úúú';
  If (page <> EMPTY_FIELD) then
    If (page OR COMMON_FLAG <> page) then
      ShowCStr(ptr_temp_screen,xpos,ypos,
               byte2hex(page AND NOT COMMON_FLAG)+' ³ ~'+
               'úúú'+'~',
               macro_background+macro_text_dis,
               macro_background+macro_text_dis)
    else
      ShowCStr(ptr_temp_screen,xpos-1,ypos,
               ' '+
               byte2hex(page AND NOT COMMON_FLAG)+' ³ ~'+
               'úúú'+'~ ',
               macro_background+macro_text_dis,
               macro_background+macro_text_dis)
  else
    ShowStr(ptr_temp_screen,xpos,ypos,
            ExpStrL('',9,' '),
            macro_background+macro_text_dis);
end;

function _gfx_bar_str(value: Byte; neg: Boolean): String;

var
  result: String;

begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:_gfx_bar_str';
{$ENDIF}
  result := '';
  If NOT neg then
    Repeat
      If (value > 15) then
        begin
          result := result+#219;
          Dec(value,15);
        end;
      If (value <= 15) and (value <> 0) then
        result := result+CHR(127+value)
    until (value <= 15)
  else Repeat
         If (value > 15) then
           begin
             result := #219+result;
             Dec(value,15);
           end;
         If (value <= 15) and (value <> 0) then
           result := CHR(158-value)+result;
       until (value <= 15);
  _gfx_bar_str := flipstr(result);
end;

function _fmreg_param(page,fmreg_hpos: Byte): Integer;

var
  result: Integer;
  fmreg_str: String;

begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:_fmreg_param';
{$ENDIF}
  fmreg_str := _fmreg_str(page);
  Case fmreg_hpos of
    {%n}
    1,2,3,4,5,8,9,14,15,16,17,
    18,21,22,27,28: result := Str2num(fmreg_str[pos5[fmreg_hpos]],16);

    {%nn}
    6,7:   result := Str2num(Copy(fmreg_str,pos5[6],2),16);
    19,20: result := Str2num(Copy(fmreg_str,pos5[19],2),16);
    34,35: result := Str2num(Copy(fmreg_str,pos5[34],2),16);

    {sw}
    10,11,12,13,23,24,
    25,26: If (fmreg_str[pos5[fmreg_hpos]] = 'û') then result := 1
              else result := 0;

    {fsl}
    29,30,31,32: begin
                   result := Str2num(Copy(fmreg_str,pos5[30],3),16);
                   If (fmreg_str[pos5[29]] = '-') then result := -result;
                 end;
    {pan}
    33: Case SYSTEM.Pos(fmreg_str[pos5[33]],_panning) of
          1: result := 0;
          2: result := -1;
          3: result := 1;
        end;
  end;
  _fmreg_param := result;
end;

procedure refresh;

var
  temp,max_value: Integer;
  d_factor: Real;
  temp_str: String;
  _add_prev_size,
  _sub_prev_xpos_a,
  _sub_prev_xpos_v: Integer;
  _axis_attr: Byte;

begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:refresh';
{$ENDIF}
  For temp := 1 to 20 do
    If (pos = temp) then attr[temp] := macro_background+macro_hi_text
    else If (temp in [1..7]) and arp_vib_mode then
           attr[temp] := macro_background+macro_text_dis
         else If (temp in [8..13]) and
                 (ptr_arpeggio_table = 0) then
               attr[temp] := macro_background+macro_text_dis
              else If (temp in [14..20]) and
                      (ptr_vibrato_table = 0) then
                     attr[temp] := macro_background+macro_text_dis
                   else attr[temp] := macro_background+macro_text;

  If (ptr_arpeggio_table <> 0) then
    begin
      attr2[1] := macro_input_bckg+macro_input;
      attr2[3] := macro_background+macro_topic;
    end
  else begin
         attr2[1] := macro_background+macro_text_dis;
         attr2[3] := macro_background+macro_text_dis;
       end;

  If (ptr_vibrato_table <> 0) then
    begin
      attr2[2] := macro_input_bckg+macro_input;
      attr2[4] := macro_background+macro_topic;
    end
  else begin
         attr2[2] := macro_background+macro_text_dis;
         attr2[4] := macro_background+macro_text_dis;
       end;

  If NOT arp_vib_mode then attr2[5] := macro_input_bckg+macro_input
  else attr2[5] := macro_background+macro_text_dis;

  If (pos = 7) then frame_type[1] := double
  else frame_type[1] := single;

  If (pos = 13) then frame_type[2] := double
  else frame_type[2] := single;

  If (pos = 20) then frame_type[3] := double
  else frame_type[3] := single;

  If NOT arp_vib_mode then
    begin
      ShowStr(ptr_temp_screen,xstart+2,ystart+1,'FM-REGiSTER',
              macro_background+macro_topic);
      ShowStr(ptr_temp_screen,xstart+2,ystart+2,'DEFiNiTiON MACRO-TABLE',
              macro_background+macro_topic);
    end
  else begin
         ShowStr(ptr_temp_screen,xstart+2,ystart+1,'FM-REGiSTER',
                 macro_background+macro_text_dis);
         ShowStr(ptr_temp_screen,xstart+2,ystart+2,'DEFiNiTiON MACRO-TABLE',
                 macro_background+macro_text_dis);
       end;

  ShowStr(ptr_temp_screen,xstart+2,ystart+3,
          ExpStrL('',78+window_area_inc_x,'Í'),
          macro_background+macro_text);

  ShowStr(ptr_temp_screen,xstart+2,ystart+10,
          ExpStrL('',78+window_area_inc_x,'Í'),
          macro_background+macro_text);

  ShowStr(ptr_temp_screen,xstart+2,ystart+22+window_area_inc_y,
          ExpStrL('',78+window_area_inc_x,'Í'),
          macro_background+macro_text);

  If NOT arp_vib_mode then
    begin
      ShowCStr(ptr_temp_screen,xstart+2,ystart+4,
               'LENGTH         ~'+
               byte2hex(songdata.instr_macros[instr].length)+' ~',
               attr[1],attr2[5]);

      ShowCStr(ptr_temp_screen,xstart+2,ystart+5,
               'LOOP BEGiN     ~'+
               byte2hex(songdata.instr_macros[instr].loop_begin)+' ~',
               attr[2],attr2[5]);

      ShowCStr(ptr_temp_screen,xstart+2,ystart+6,
               'LOOP LENGTH    ~'+
               byte2hex(songdata.instr_macros[instr].loop_length)+' ~',
               attr[3],attr2[5]);

      ShowCStr(ptr_temp_screen,xstart+2,ystart+7,
               'KEY-OFF        ~'+
               byte2hex(songdata.instr_macros[instr].keyoff_pos)+' ~',
               attr[4],attr2[5]);

      ShowCStr(ptr_temp_screen,xstart+2,ystart+8,
               'ARPEGGiO TABLE ~'+
               byte2hex(ptr_arpeggio_table)+' ~',
               attr[5],attr2[5]);

      ShowCStr(ptr_temp_screen,xstart+2,ystart+9,
               'ViBRATO TABLE  ~'+
               byte2hex(ptr_vibrato_table)+' ~',
               attr[6],attr2[5]);

      _add_prev_size := window_area_inc_x DIV 2;
      _sub_prev_xpos_a := 0;
      _sub_prev_xpos_v := 0;
    end
  else begin
         _add_prev_size := 0;
         _sub_prev_xpos_a := 20;
         _sub_prev_xpos_v := -3;
       end;

  ShowStr(ptr_temp_screen,xstart+48+window_area_inc_x,ystart+2,'ARPEGGiO ('+
          byte2hex(ptr_arpeggio_table)+')',
          attr2[3]);

  ShowCStr(ptr_temp_screen,xstart+48+window_area_inc_x,ystart+4,
           'LENGTH      ~'+
           byte2hex(songdata.macro_table[ptr_arpeggio_table].
                   arpeggio.length)+' ~',
           attr[8],attr2[1]);

  ShowCStr(ptr_temp_screen,xstart+48+window_area_inc_x,ystart+5,
           'SPEED       ~'+
           byte2hex(songdata.macro_table[ptr_arpeggio_table].
                   arpeggio.speed)+' ~',
           attr[9],attr2[1]);

  ShowCStr(ptr_temp_screen,xstart+48+window_area_inc_x,ystart+6,
           'LOOP BEGiN  ~'+
           byte2hex(songdata.macro_table[ptr_arpeggio_table].
                   arpeggio.loop_begin)+' ~',
           attr[10],attr2[1]);

  ShowCStr(ptr_temp_screen,xstart+48+window_area_inc_x,ystart+7,
           'LOOP LENGTH ~'+
           byte2hex(songdata.macro_table[ptr_arpeggio_table].
                   arpeggio.loop_length)+' ~',
           attr[11],attr2[1]);

  ShowCStr(ptr_temp_screen,xstart+48+window_area_inc_x,ystart+8,
           'KEY-OFF     ~'+
           byte2hex(songdata.macro_table[ptr_arpeggio_table].
                   arpeggio.keyoff_pos)+' ~',
           attr[12],attr2[1]);

  ShowStr(ptr_temp_screen,xstart+65+window_area_inc_x,ystart+2,'ViBRATO ('+
          byte2hex(ptr_vibrato_table)+')',
          attr2[4]);

  ShowCStr(ptr_temp_screen,xstart+65+window_area_inc_x,ystart+4,
           'LENGTH      ~'+
           byte2hex(songdata.macro_table[ptr_vibrato_table].
                    vibrato.length)+' ~',
           attr[14],attr2[2]);

  ShowCStr(ptr_temp_screen,xstart+65+window_area_inc_x,ystart+5,
           'SPEED       ~'+
           byte2hex(songdata.macro_table[ptr_vibrato_table].
                    vibrato.speed)+' ~',
           attr[15],attr2[2]);

  ShowCStr(ptr_temp_screen,xstart+65+window_area_inc_x,ystart+6,
           'DELAY       ~'+
           byte2hex(songdata.macro_table[ptr_vibrato_table].
                    vibrato.delay)+' ~',
           attr[16],attr2[2]);

  ShowCStr(ptr_temp_screen,xstart+65+window_area_inc_x,ystart+7,
           'LOOP BEGiN  ~'+
           byte2hex(songdata.macro_table[ptr_vibrato_table].
                    vibrato.loop_begin)+' ~',
           attr[17],attr2[2]);

  ShowCStr(ptr_temp_screen,xstart+65+window_area_inc_x,ystart+8,
           'LOOP LENGTH ~'+
           byte2hex(songdata.macro_table[ptr_vibrato_table].
                    vibrato.loop_length)+' ~',
           attr[18],attr2[2]);

  ShowCStr(ptr_temp_screen,xstart+65+window_area_inc_x,ystart+9,
           'KEY-OFF     ~'+
           byte2hex(songdata.macro_table[ptr_vibrato_table].
                    vibrato.keyoff_pos)+' ~',
           attr[19],attr2[2]);

  fr_setting.update_area := FALSE;
  fr_setting.shadow_enabled := FALSE;

  Frame(ptr_temp_screen,xstart+2,ystart+11,
        xstart+42+_add_prev_size*2,ystart+21+window_area_inc_y,
        attr[7],'',
        macro_background+macro_text,frame_type[1]);

  Frame(ptr_temp_screen,xstart+48+window_area_inc_x,ystart+11,
        xstart+59+_add_prev_size*2,ystart+21+window_area_inc_y,
        attr[13],'',
        macro_background+macro_text,frame_type[2]);

  Frame(ptr_temp_screen,xstart+65+window_area_inc_x,ystart+11,
        xstart+76+_add_prev_size*2,ystart+21+window_area_inc_y,
        attr[20],'',
        macro_background+macro_text,frame_type[3]);

  fr_setting.update_area := TRUE;
  fr_setting.shadow_enabled := TRUE;

  show_queue(xstart+4,ystart+11,9+window_area_inc_y,fmreg_page,255,1);
  If NOT arp_vib_mode then
    begin
      HScrollBar(ptr_temp_screen,xstart+29+_add_prev_size*2,ystart+21+window_area_inc_y,
                 13,35,fmreg_hpos,WORD_NULL,
                 macro_scrbar_bckg+macro_scrbar_text,
                 macro_scrbar_bckg+macro_scrbar_mark);
      VScrollBar(ptr_temp_screen,xstart+43+_add_prev_size*2,ystart+12,
                 9+window_area_inc_y,255,fmreg_page,WORD_NULL,
                 macro_scrbar_bckg+macro_scrbar_text,
                 macro_scrbar_bckg+macro_scrbar_mark);
    end
  else
    begin
      HScrollBar(ptr_temp_screen,xstart+29+_add_prev_size*2,ystart+21+window_area_inc_y,
                 13,35,fmreg_hpos,WORD_NULL,
                 macro_background+macro_text_dis,
                 macro_background+macro_text_dis);
      VScrollBar(ptr_temp_screen,xstart+43+_add_prev_size*2,ystart+12,
                 9+window_area_inc_y,255,fmreg_page,WORD_NULL,
                 macro_background+macro_text_dis,
                 macro_background+macro_text_dis);
    end;

  If (pos = 7) then
    ShowStr(ptr_temp_screen,xstart+2+8,ystart+11,
            Copy(_str1('Í'),fmreg_left_margin,31),
            attr[7])
  else
    ShowStr(ptr_temp_screen,xstart+2+8,ystart+11,
            Copy(_str1('Ä'),fmreg_left_margin,31),
            attr[7]);

  If (ptr_arpeggio_table <> 0) then
    begin
      show_queue(xstart+50+_add_prev_size*2,ystart+11,9+window_area_inc_y,arpeggio_page,255,2);
      VScrollBar(ptr_temp_screen,xstart+60+_add_prev_size*2,ystart+12,
                 9+window_area_inc_y,255,arpeggio_page,WORD_NULL,
                 macro_scrbar_bckg+macro_scrbar_text,
                 macro_scrbar_bckg+macro_scrbar_mark)
    end
  else
    begin
      show_queue(xstart+50+_add_prev_size*2,ystart+11,9+window_area_inc_y,1,255,3);
      VScrollBar(ptr_temp_screen,xstart+60+_add_prev_size*2,ystart+12,
                 9+window_area_inc_y,255,1,WORD_NULL,
                 macro_background+macro_text_dis,
                 macro_background+macro_text_dis);
    end;

  If (ptr_vibrato_table <> 0) then
    begin
      show_queue(xstart+67+_add_prev_size*2,ystart+11,9+window_area_inc_y,vibrato_page,255,4);
      VScrollBar(ptr_temp_screen,xstart+77+_add_prev_size*2,ystart+12,
                 9+window_area_inc_y,255,vibrato_page,WORD_NULL,
                 macro_scrbar_bckg+macro_scrbar_text,
                 macro_scrbar_bckg+macro_scrbar_mark);
    end
  else
    begin
      show_queue(xstart+67+_add_prev_size*2,ystart+11,9+window_area_inc_y,1,255,5);
      VScrollBar(ptr_temp_screen,xstart+77+_add_prev_size*2,ystart+12,
                 9+window_area_inc_y,255,1,WORD_NULL,
                 macro_background+macro_text_dis,
                 macro_background+macro_text_dis);
    end;

  If (pos <> 7) then
    ShowStr(ptr_temp_screen,xstart+2,ystart+23+window_area_inc_y,
            ExpStrR(macro_table_hint_str[pos],77,' '),
            macro_background+macro_hint)
  else ShowStr(ptr_temp_screen,xstart+2,ystart+23+window_area_inc_y,
               ExpStrR(macro_table_hint_str[20+fmreg_hpos],77,' '),
               macro_background+macro_hint);

  If (pos in [1..7]) then
    begin
      ShowStr(ptr_temp_screen,xstart+32+_add_prev_size,ystart+3,
              'ý',
              macro_background+macro_text);
      ShowStr(ptr_temp_screen,xstart+32+_add_prev_size,ystart+10,
              'ü',
              macro_background+macro_text);

      If NOT (fmreg_hpos in [29..33]) then
        begin
          ShowVStr(ptr_temp_screen,xstart+22,ystart+4,
                   '³³³³³ž',
                   macro_background+macro_text);
          ShowVStr(ptr_temp_screen,xstart+42+window_area_inc_x,ystart+4,
                   '³³³³³ž',
                   macro_background+macro_text);
        end
      else begin
             ShowVStr(ptr_temp_screen,xstart+22,ystart+4,
                      '³³ž³³³',
                      macro_background+macro_text);
             ShowVStr(ptr_temp_screen,xstart+42+window_area_inc_x,ystart+4,
                      '³³ž³³³',
                      macro_background+macro_text);
           end;

      max_value := 0;
      For temp := 1 to 255 do
        If (Abs(_fmreg_param(temp,fmreg_hpos)) > max_value) then
          max_value := Abs(_fmreg_param(temp,fmreg_hpos));

      If NOT (fmreg_hpos in [29..33]) then
        begin
          ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1,ystart+4,
                  ExpStrR(ExpStrL(Num2Str(max_value,16),2,'0'),3,' '),
                  macro_background+macro_topic);
          ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1,ystart+5,
                  '+',
                  macro_background+macro_topic);
          ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1,ystart+8,
                  ' ',
                  macro_background+macro_topic);
          ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1,ystart+9,
                  ExpStrR('',3,' '),
                  macro_background+macro_topic);
        end
      else
        begin
          ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1,ystart+4,
                  ExpStrR(ExpStrL(Num2Str(max_value,16),2,'0'),3,' '),
                  macro_background+macro_topic);
          ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1,ystart+5,
                  '+',
                  macro_background+macro_topic);
          ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1,ystart+8,
                  '-',
                  macro_background+macro_topic);
          ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1,ystart+9,
                  ExpStrR(ExpStrL(Num2Str(max_value,16),2,'0'),3,' '),
                  macro_background+macro_topic);
        end;

      If NOT (fmreg_hpos in [29..33]) then
        d_factor := 90/min(max_value,1)
      else d_factor := 45/min(max_value,1);

      If NOT (fmreg_hpos in [29..33]) then
        For temp := -9-_add_prev_size to 9+_add_prev_size do
          If (fmreg_page+temp >= 1) and (fmreg_page+temp <= 255) then
            If NOT _dis_fmreg_col(fmreg_hpos) then
              ShowVStr(ptr_temp_screen,xstart+32+temp+_add_prev_size,ystart+4,
                       ExpStrL(_gfx_bar_str(Round(_fmreg_param(fmreg_page+temp,fmreg_hpos)*d_factor),FALSE),6,' '),
                       LO(fmreg_def_attr(fmreg_page+temp)))
            else
              ShowVStr(ptr_temp_screen,xstart+32+temp+_add_prev_size,ystart+4,
                       ExpStrL(_gfx_bar_str(Round(_fmreg_param(fmreg_page+temp,fmreg_hpos)*d_factor),FALSE),6,' '),
                       macro_background+macro_text_dis)
          else ShowVStr(ptr_temp_screen,xstart+32+temp+_add_prev_size,ystart+4,
                        ExpStrL('',6,' '),
                        macro_background+macro_text)
      else For temp := -9-_add_prev_size to 9+_add_prev_size do
             If (fmreg_page+temp >= 1) and (fmreg_page+temp <= 255) then
               If (Round(_fmreg_param(fmreg_page+temp,fmreg_hpos)*d_factor) >= 0) then
                 If NOT _dis_fmreg_col(fmreg_hpos) then
                   ShowVStr(ptr_temp_screen,xstart+32+temp+_add_prev_size,ystart+4,
                            ExpStrR(ExpStrL(_gfx_bar_str(Round(_fmreg_param(fmreg_page+temp,fmreg_hpos)*d_factor),FALSE),3,' '),6,' '),
                            LO(fmreg_def_attr(fmreg_page+temp)))
                 else
                   ShowVStr(ptr_temp_screen,xstart+32+temp+_add_prev_size,ystart+4,
                            ExpStrR(ExpStrL(_gfx_bar_str(Round(_fmreg_param(fmreg_page+temp,fmreg_hpos)*d_factor),FALSE),3,' '),6,' '),
                            macro_background+macro_text_dis)
               else If NOT _dis_fmreg_col(fmreg_hpos) then
                      ShowVStr(ptr_temp_screen,xstart+32+temp+_add_prev_size,ystart+4,
                               ExpStrL(ExpStrR(_gfx_bar_str(Round(Abs(_fmreg_param(fmreg_page+temp,fmreg_hpos))*d_factor),TRUE),3,' '),6,' '),
                               LO(fmreg_def_attr(fmreg_page+temp)))
                    else
                      ShowVStr(ptr_temp_screen,xstart+32+temp+_add_prev_size,ystart+4,
                               ExpStrL(ExpStrR(_gfx_bar_str(Round(Abs(_fmreg_param(fmreg_page+temp,fmreg_hpos))*d_factor),TRUE),3,' '),6,' '),
                               macro_background+macro_text_dis)
             else ShowVStr(ptr_temp_screen,xstart+32+temp+_add_prev_size,ystart+4,
                           ExpStrR('',6,' '),
                           macro_background+macro_text);
    end;

  If (pos in [8..13]) or arp_vib_mode then
    begin
      If NOT (pos in [8..13]) then _axis_attr := macro_background+macro_topic
      else begin
             ShowStr(ptr_temp_screen,xstart+32+_add_prev_size-_sub_prev_xpos_a,ystart+3,
                     'ý',
                     macro_background+macro_text);
             ShowStr(ptr_temp_screen,xstart+32+_add_prev_size-_sub_prev_xpos_a,ystart+10,
                     'ü',
                     macro_background+macro_text);
           end;

      If (pos in [8..13]) then
        If arp_vib_mode then _axis_attr := macro_background+macro_hi_text
        else _axis_attr := macro_background+macro_text
      else _axis_attr := macro_background+macro_text;

      ShowVStr(ptr_temp_screen,xstart+22-_sub_prev_xpos_a,ystart+4,
               '³³³³³ž',
               _axis_attr);
      ShowVStr(ptr_temp_screen,xstart+42+window_area_inc_x-_sub_prev_xpos_a,ystart+4,
               '³³³³³ž',
               _axis_attr);

      max_value := 0;
      For temp := 1 to 255 do
        If (songdata.macro_table[ptr_arpeggio_table].
            arpeggio.data[temp] > max_value) then
          If (songdata.macro_table[ptr_arpeggio_table].
              arpeggio.data[temp] < $80) then
            max_value := Abs(songdata.macro_table[ptr_arpeggio_table].
                             arpeggio.data[temp]);

       If NOT arp_vib_mode then
         begin
           ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1-_sub_prev_xpos_a,ystart+4,
                   ExpStrR(Num2Str(max_value,10),3,' '),
                   macro_background+macro_topic);
           ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1-_sub_prev_xpos_a,ystart+5,
                   '+ ',
                   macro_background+macro_topic);
           ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1-_sub_prev_xpos_a,ystart+8,
                   '  ',
                   macro_background+macro_topic);
           ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1-_sub_prev_xpos_a,ystart+9,
                   ExpStrR('',3,' '),
                   macro_background+macro_topic);
         end
       else If (pos in [8..13]) then
              begin
                ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1-_sub_prev_xpos_a,ystart+4,
                        ExpStrR(Num2Str(max_value,10),3,' '),
                        macro_background+macro_hi_text);
                ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1-_sub_prev_xpos_a,ystart+5,
                        '+ ',
                        macro_background+macro_hi_text);
                ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1-_sub_prev_xpos_a,ystart+8,
                        '  ',
                        macro_background+macro_hi_text);
                ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1-_sub_prev_xpos_a,ystart+9,
                        ExpStrR('',3,' '),
                        macro_background+macro_hi_text);
              end;

      d_factor := 90/min(max_value,1);
      For temp := -9-_add_prev_size to 9+_add_prev_size do
        If (arpeggio_page+temp >= 1) and (arpeggio_page+temp <= 255) then
          If (songdata.macro_table[ptr_arpeggio_table].
              arpeggio.data[arpeggio_page+temp] < $80) then
            ShowVStr(ptr_temp_screen,xstart+32+temp+_add_prev_size-_sub_prev_xpos_a,ystart+4,
                     ExpStrL(_gfx_bar_str(Round(songdata.macro_table[ptr_arpeggio_table].
                                                arpeggio.data[arpeggio_page+temp]*d_factor),FALSE),6,' '),
                     LO(arpeggio_def_attr(arpeggio_page+temp)))
          else ShowVStr(ptr_temp_screen,xstart+32+temp+_add_prev_size-_sub_prev_xpos_a,ystart+4,
                        ExpStrL(FilterStr(note_layout[songdata.macro_table[ptr_arpeggio_table].
                                                      arpeggio.data[arpeggio_page+temp]-$80],'-','ñ'),6,' '),
                        LO(arpeggio_def_attr(arpeggio_page+temp)))
        else ShowVStr(ptr_temp_screen,xstart+32+temp+_add_prev_size-_sub_prev_xpos_a,ystart+4,
                      ExpStrL('',6,' '),
                      macro_background+macro_text);
    end;

  If (pos in [14..20]) or arp_vib_mode then
    begin
      If NOT (pos in [14..20]) then _axis_attr := macro_background+macro_text
      else begin
             ShowStr(ptr_temp_screen,xstart+32+_add_prev_size-_sub_prev_xpos_v,ystart+3,
                     'ý',
                     macro_background+macro_text);
             ShowStr(ptr_temp_screen,xstart+32+_add_prev_size-_sub_prev_xpos_v,ystart+10,
                     'ü',
                     macro_background+macro_text);
           end;

      If (pos in [14..20]) then
        If arp_vib_mode then _axis_attr := macro_background+macro_hi_text
        else _axis_attr := macro_background+macro_text
      else _axis_attr := macro_background+macro_text;

      ShowVStr(ptr_temp_screen,xstart+22-_sub_prev_xpos_v,ystart+4,
               '³³ž³³³',
               _axis_attr);
      ShowVStr(ptr_temp_screen,xstart+42+window_area_inc_x-_sub_prev_xpos_v,ystart+4,
               '³³ž³³³',
               _axis_attr);

      max_value := 0;
      For temp := 1 to 255 do
        If (Abs(songdata.macro_table[ptr_vibrato_table].
                vibrato.data[temp]) > max_value) then
          max_value := Abs(songdata.macro_table[ptr_vibrato_table].
                           vibrato.data[temp]);

      If NOT arp_vib_mode then
        begin
          ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1-_sub_prev_xpos_v,ystart+4,
                  ExpStrR(ExpStrL(Num2Str(max_value,16),2,'0'),3,' '),
                  macro_background+macro_topic);
          ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1-_sub_prev_xpos_v,ystart+5,
                  '+',
                  macro_background+macro_topic);
          ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1-_sub_prev_xpos_v,ystart+8,
                  '-',
                  macro_background+macro_topic);
          ShowStr(ptr_temp_screen,xstart+42+window_area_inc_x+1-_sub_prev_xpos_v,ystart+9,
                  ExpStrR(ExpStrL(Num2Str(max_value,16),2,'0'),3,' '),
                  macro_background+macro_topic);
        end
      else If (pos in [14..20]) then
             begin
               ShowStr(ptr_temp_screen,xstart+20-_sub_prev_xpos_v,ystart+4,
                       ExpStrL(ExpStrL(Num2Str(max_value,16),2,'0'),2,' '),
                       macro_background+macro_hi_text);
               ShowStr(ptr_temp_screen,xstart+20-_sub_prev_xpos_v,ystart+5,
                       ' +',
                       macro_background+macro_hi_text);
               ShowStr(ptr_temp_screen,xstart+20-_sub_prev_xpos_v,ystart+8,
                       ' -',
                       macro_background+macro_hi_text);
               ShowStr(ptr_temp_screen,xstart+20-_sub_prev_xpos_v,ystart+9,
                       ExpStrL(ExpStrL(Num2Str(max_value,16),2,'0'),2,' '),
                       macro_background+macro_hi_text);
             end;

      d_factor := 45/min(max_value,1);
      For temp := -9-_add_prev_size to 9+_add_prev_size do
        If (vibrato_page+temp >= 1) and (vibrato_page+temp <= 255) then
          If (Round(songdata.macro_table[ptr_vibrato_table].
                    vibrato.data[vibrato_page+temp]*d_factor) >= 0) then
            ShowVStr(ptr_temp_screen,xstart+32+temp+_add_prev_size-_sub_prev_xpos_v,ystart+4,
                     ExpStrR(ExpStrL(_gfx_bar_str(Round(songdata.macro_table[ptr_vibrato_table].
                                                        vibrato.data[vibrato_page+temp]*d_factor),FALSE),3,' '),6,' '),
                     LO(vibrato_def_attr(vibrato_page+temp)))
          else ShowVStr(ptr_temp_screen,xstart+32+temp+_add_prev_size-_sub_prev_xpos_v,ystart+4,
                        ExpStrL(ExpStrR(_gfx_bar_str(Round(Abs(songdata.macro_table[ptr_vibrato_table].
                                                               vibrato.data[vibrato_page+temp])*d_factor),TRUE),3,' '),6,' '),
                        LO(vibrato_def_attr(vibrato_page+temp)))
        else ShowVStr(ptr_temp_screen,xstart+32+temp+_add_prev_size-_sub_prev_xpos_v,ystart+4,
                      ExpStrR('',6,' '),
                      macro_background+macro_text);
    end;

  Case songdata.instr_data[current_inst].perc_voice of
    0: ShowCStr(ptr_temp_screen,
                xstart+01,ystart+24+window_area_inc_y,
                ' [MELODiC] ',
                macro_background+macro_border,
                macro_background+macro_hi_text);
    1: ShowCStr(ptr_temp_screen,
                xstart+01,ystart+24+window_area_inc_y,
                ' [PERC:BD] ',
                macro_background+macro_border,
                macro_background+macro_hi_text);
    2: ShowCStr(ptr_temp_screen,
                xstart+01,ystart+24+window_area_inc_y,
                ' [PERC:SD] ',
                macro_background+macro_border,
                macro_background+macro_hi_text);
    3: ShowCStr(ptr_temp_screen,
                 xstart+01,ystart+24+window_area_inc_y,
                ' [PERC:TT] ',
                macro_background+macro_border,
                macro_background+macro_hi_text);
    4: ShowCStr(ptr_temp_screen,
                xstart+01,ystart+24+window_area_inc_y,
                ' [PERC:TC] ',
                macro_background+macro_border,
                macro_background+macro_hi_text);
    5: ShowCStr(ptr_temp_screen,
                xstart+01,ystart+24+window_area_inc_y,
                ' [PERC:HH] ',
                macro_background+macro_border,
                macro_background+macro_hi_text);
  end;

  If (songdata.instr_macros[current_inst].length <> 0) then temp_str := ' [~MACRO:FM'
  else temp_str := ' ';

  With songdata.macro_table[ptr_arpeggio_table].arpeggio do
    If (songdata.instr_macros[current_inst].arpeggio_table <> 0) then
      If (temp_str <> ' ') then temp_str := temp_str+'+ARP'
      else temp_str := temp_str+'[~MACRO:ARP';

  With songdata.macro_table[ptr_vibrato_table].vibrato do
    If (songdata.instr_macros[current_inst].vibrato_table <> 0) then
      If (temp_str <> ' ') then temp_str := temp_str+'+ViB'
      else temp_str := temp_str+'[~MACRO:ViB';

  If (temp_str <> ' ') then temp_str := temp_str+'~] ';

  ShowCStr(ptr_temp_screen,xstart+11,ystart+24+window_area_inc_y,ExpStrR(temp_str,21+2,'Í'),
           macro_background+macro_border,
           macro_background+macro_hi_text);

  ShowCStr(ptr_temp_screen,xstart+window_area_inc_x+66,ystart+24+window_area_inc_y,
           ExpStrL(' ~[SPEED:'+Num2str(songdata.tempo*songdata.macro_speedup,10)+#3+']~ ',17,'Í'),
           macro_background+macro_border,
           macro_background+macro_hi_text);

  _preview_indic_proc(0);
  move2screen_alt;
end;

function hex(chr: Char): Byte;
begin hex := PRED(SYSTEM.Pos(UpCase(chr),_hex)); end;

procedure copy_object;

var
  temp: Byte;

begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:copy_object';
{$ENDIF}

  Case clipboard.object_type of
    objMacroTableLine:
      Case clipboard.mcrtab_type of
        mttFM_reg_table:
          clipboard.fmreg_table.data[1] :=
            songdata.instr_macros[instr].data[fmreg_page];

        mttArpeggio_table:
          clipboard.macro_table.arpeggio.data[1] :=
            songdata.macro_table[ptr_arpeggio_table].
            arpeggio.data[arpeggio_page];

        mttVibrato_table:
          clipboard.macro_table.vibrato.data[1] :=
            songdata.macro_table[ptr_vibrato_table].
            vibrato.data[vibrato_page];
      end;

    objMacroTableColumn:
      Case clipboard.mcrtab_type of
        mttFM_reg_table:
          begin
            clipboard.fmtab_def_typ := fmreg_hpos;
            For temp := 1 to 255 do
              clipboard.fmreg_table.data[temp] :=
                songdata.instr_macros[instr].data[temp];
          end;

        mttArpeggio_table:
          clipboard.macro_table.arpeggio :=
            songdata.macro_table[ptr_arpeggio_table].arpeggio;

        mttVibrato_table:
          clipboard.macro_table.vibrato :=
            songdata.macro_table[ptr_vibrato_table].vibrato;
      end;

    objMacroTable:
      Case clipboard.mcrtab_type of
        mttFM_reg_table:
          clipboard.fmreg_table :=
            songdata.instr_macros[instr];

        mttArpeggio_table:
          clipboard.macro_table.arpeggio :=
            songdata.macro_table[ptr_arpeggio_table].arpeggio;

        mttVibrato_table:
          clipboard.macro_table.vibrato :=
            songdata.macro_table[ptr_vibrato_table].vibrato;
      end;
  end;
end;

procedure paste_object;

var
  temp: Byte;

begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:paste_object';
{$ENDIF}

  Case clipboard.object_type of
    objMacroTableLine:
      Case clipboard.mcrtab_type of
        mttFM_reg_table:
          If (pos = 7) then
            begin
              temp := songdata.instr_macros[instr].data[fmreg_page].
                      fm_data.FEEDBACK_FM;
              songdata.instr_macros[instr].data[fmreg_page] :=
                clipboard.fmreg_table.data[1];
              songdata.instr_macros[instr].data[fmreg_page].
                fm_data.FEEDBACK_FM := temp AND $0c0+
              songdata.instr_macros[instr].data[fmreg_page].
                fm_data.FEEDBACK_FM;
            end;

        mttArpeggio_table:
          If (pos = 13) then
            songdata.macro_table[ptr_arpeggio_table].
            arpeggio.data[arpeggio_page] :=
              clipboard.macro_table.arpeggio.data[1];

        mttVibrato_table:
          If (pos = 20) then
            songdata.macro_table[ptr_vibrato_table].
            vibrato.data[vibrato_page] :=
              clipboard.macro_table.vibrato.data[1];
      end;

    objMacroTableColumn:
      Case clipboard.mcrtab_type of
        mttFM_reg_table:
          For temp := 1 to 255 do
            With songdata.instr_macros[instr].data[temp] do
              Case clipboard.fmtab_def_typ of
                1: fm_data.ATTCK_DEC_modulator :=
                   clipboard.fmreg_table.data[temp].fm_data.ATTCK_DEC_modulator AND $0f0+
                   fm_data.ATTCK_DEC_modulator AND $0f;
                2: fm_data.ATTCK_DEC_modulator :=
                   fm_data.ATTCK_DEC_modulator AND $0f0+
                   clipboard.fmreg_table.data[temp].fm_data.ATTCK_DEC_modulator AND $0f;
                3: fm_data.SUSTN_REL_modulator :=
                   clipboard.fmreg_table.data[temp].fm_data.SUSTN_REL_modulator AND $0f0+
                   fm_data.SUSTN_REL_modulator AND $0f;
                4: fm_data.SUSTN_REL_modulator :=
                   fm_data.SUSTN_REL_modulator AND $0f0+
                   clipboard.fmreg_table.data[temp].fm_data.SUSTN_REL_modulator AND $0f;
                5: fm_data.WAVEFORM_modulator :=
                   clipboard.fmreg_table.data[temp].fm_data.WAVEFORM_modulator;
                6,
                7: fm_data.KSL_VOLUM_modulator :=
                   fm_data.KSL_VOLUM_modulator AND $0c0+
                   clipboard.fmreg_table.data[temp].fm_data.KSL_VOLUM_modulator AND $3f;
                8: fm_data.KSL_VOLUM_modulator :=
                   fm_data.KSL_VOLUM_modulator AND $3f+
                   clipboard.fmreg_table.data[temp].fm_data.KSL_VOLUM_modulator AND $0c0;
                9: fm_data.AM_VIB_EG_modulator :=
                   fm_data.AM_VIB_EG_modulator AND $0f0+
                   clipboard.fmreg_table.data[temp].fm_data.AM_VIB_EG_modulator AND $0f;
               10: fm_data.AM_VIB_EG_modulator :=
                   fm_data.AM_VIB_EG_modulator AND $7f+
                   clipboard.fmreg_table.data[temp].fm_data.AM_VIB_EG_modulator AND $80;
               11: fm_data.AM_VIB_EG_modulator :=
                   fm_data.AM_VIB_EG_modulator AND $0bf+
                   clipboard.fmreg_table.data[temp].fm_data.AM_VIB_EG_modulator AND $40;
               12: fm_data.AM_VIB_EG_modulator :=
                   fm_data.AM_VIB_EG_modulator AND $0ef+
                   clipboard.fmreg_table.data[temp].fm_data.AM_VIB_EG_modulator AND $10;
               13: fm_data.AM_VIB_EG_modulator :=
                   fm_data.AM_VIB_EG_modulator AND $0df+
                   clipboard.fmreg_table.data[temp].fm_data.AM_VIB_EG_modulator AND $20;
               14: fm_data.ATTCK_DEC_carrier :=
                   clipboard.fmreg_table.data[temp].fm_data.ATTCK_DEC_carrier AND $0f0+
                   fm_data.ATTCK_DEC_carrier AND $0f;
               15: fm_data.ATTCK_DEC_carrier :=
                   fm_data.ATTCK_DEC_carrier AND $0f0+
                   clipboard.fmreg_table.data[temp].fm_data.ATTCK_DEC_carrier AND $0f;
               16: fm_data.SUSTN_REL_carrier :=
                   clipboard.fmreg_table.data[temp].fm_data.SUSTN_REL_carrier AND $0f0+
                   fm_data.SUSTN_REL_carrier AND $0f;
               17: fm_data.SUSTN_REL_carrier :=
                   fm_data.SUSTN_REL_carrier AND $0f0+
                   clipboard.fmreg_table.data[temp].fm_data.SUSTN_REL_carrier AND $0f;
               18: fm_data.WAVEFORM_carrier :=
                   clipboard.fmreg_table.data[temp].fm_data.WAVEFORM_carrier;
               19,
               20: fm_data.KSL_VOLUM_carrier :=
                   fm_data.KSL_VOLUM_carrier AND $0c0+
                   clipboard.fmreg_table.data[temp].fm_data.KSL_VOLUM_carrier AND $3f;
               21: fm_data.KSL_VOLUM_carrier :=
                   fm_data.KSL_VOLUM_carrier AND $3f+
                   clipboard.fmreg_table.data[temp].fm_data.KSL_VOLUM_carrier AND $0c0;
               22: fm_data.AM_VIB_EG_carrier :=
                   fm_data.AM_VIB_EG_carrier AND $0f0+
                   clipboard.fmreg_table.data[temp].fm_data.AM_VIB_EG_carrier AND $0f;
               23: fm_data.AM_VIB_EG_carrier :=
                   fm_data.AM_VIB_EG_carrier AND $7f+
                   clipboard.fmreg_table.data[temp].fm_data.AM_VIB_EG_carrier AND $80;
               24: fm_data.AM_VIB_EG_carrier :=
                   fm_data.AM_VIB_EG_carrier AND $0bf+
                   clipboard.fmreg_table.data[temp].fm_data.AM_VIB_EG_carrier AND $40;
               25: fm_data.AM_VIB_EG_carrier :=
                   fm_data.AM_VIB_EG_carrier AND $0ef+
                   clipboard.fmreg_table.data[temp].fm_data.AM_VIB_EG_carrier AND $10;
               26: fm_data.AM_VIB_EG_carrier :=
                   fm_data.AM_VIB_EG_carrier AND $0df+
                   clipboard.fmreg_table.data[temp].fm_data.AM_VIB_EG_carrier AND $20;
               27: fm_data.FEEDBACK_FM :=
                   fm_data.FEEDBACK_FM AND $0fe+
                   clipboard.fmreg_table.data[temp].fm_data.FEEDBACK_FM AND 1;
               28: fm_data.FEEDBACK_FM :=
                   fm_data.FEEDBACK_FM AND $0c1+
                   clipboard.fmreg_table.data[temp].fm_data.FEEDBACK_FM AND $03e;
               29,30,31,
               32: freq_slide :=
                   clipboard.fmreg_table.data[temp].freq_slide;
               33: panning :=
                   clipboard.fmreg_table.data[temp].panning;
               34,
               35: duration :=
                   clipboard.fmreg_table.data[temp].duration;
              end;

        mttArpeggio_table:
          If (pos in [8..13]) then
            For temp := 1 to 255 do
              songdata.macro_table[ptr_arpeggio_table].
              arpeggio.data[temp] :=
                clipboard.macro_table.arpeggio.data[temp];

        mttVibrato_table:
          If (pos in [14..20]) then
            For temp := 1 to 255 do
              songdata.macro_table[ptr_vibrato_table].
              vibrato.data[temp] :=
                clipboard.macro_table.vibrato.data[temp];
      end;

    objMacroTable:
      Case clipboard.mcrtab_type of
        mttFM_reg_table:
          If (pos in [1..7]) then
            songdata.instr_macros[instr] :=
              clipboard.fmreg_table;

        mttArpeggio_table:
          If (pos in [8..13]) then
            songdata.macro_table[ptr_arpeggio_table].arpeggio :=
              clipboard.macro_table.arpeggio;

        mttVibrato_table:
          If (pos in [14..20]) then
            songdata.macro_table[ptr_vibrato_table].vibrato :=
              clipboard.macro_table.vibrato;
      end;
  end;
end;

procedure _scroll_cur_left;
begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:_scroll_cur_left';
{$ENDIF}
  Repeat
    If (fmreg_cursor_pos > 1) then Dec(fmreg_cursor_pos)
    else Dec(fmreg_left_margin);
  until (fmreg_str[PRED(fmreg_left_margin+fmreg_cursor_pos-1)] = ' ') or
        (fmreg_left_margin+fmreg_cursor_pos-1 = 1);
  fmreg_cursor_pos := pos5[fmreg_hpos]-fmreg_left_margin+1;
end;

procedure _scroll_cur_right;
begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR:_scroll_cur_right';
{$ENDIF}
  Repeat
    If (fmreg_cursor_pos < max(57,31+window_area_inc_x)) then Inc(fmreg_cursor_pos)
    else Inc(fmreg_left_margin);
  until (fmreg_str[SUCC(fmreg_left_margin+fmreg_cursor_pos-1)] = ' ') or
        (fmreg_left_margin+fmreg_cursor_pos-1 = 57);
  fmreg_cursor_pos := pos5[fmreg_hpos]-fmreg_left_margin+1;
end;

function _inc(value,limit: Integer): Integer;
begin
  If (value < limit) then Inc(value);
  _inc := value;
end;

function _dec(value,limit: Integer): Integer;
begin
  If (value > limit) then Dec(value);
  _dec := value;
end;

function _check_macro_speed_change: Boolean;
begin
  _check_macro_speed_change := FALSE;
  Case is_environment.keystroke of
    kCtLbr:  If shift_pressed then
               begin
                 If (songdata.macro_speedup > 1) then
                   Dec(songdata.macro_speedup);
                 macro_speedup := songdata.macro_speedup;
                 keyboard_reset_buffer;
               end
             else If (_4op_to_test = 0) then
                    If (current_inst > 1) then
                      begin
                        Dec(current_inst);
                        instrum_page := current_inst;
                        STATUS_LINE_refresh;
                        keyboard_reset_buffer;
                        _check_macro_speed_change := TRUE;
                      end;

    kCtRbr:  If shift_pressed then
               begin
                 Inc(songdata.macro_speedup);
                 If (calc_max_speedup(songdata.tempo) < songdata.macro_speedup) then
                   songdata.macro_speedup := calc_max_speedup(songdata.tempo);
                 macro_speedup := songdata.macro_speedup;
                 keyboard_reset_buffer;
               end
             else If (_4op_to_test = 0) then
                    If (current_inst < 255) then
                      begin
                        Inc(current_inst);
                        instrum_page := current_inst;
                        reset_4op_to_test(1,BYTE_NULL);
                        STATUS_LINE_refresh;
                        keyboard_reset_buffer;
                        _check_macro_speed_change := TRUE;
                      end;
  end;
end;

procedure _check_fmreg_general_keys;
begin
  Case is_environment.keystroke of
    kCtHOME:  If NOT shift_pressed then
                If (songdata.instr_macros[instr].length > 0) then
                  Dec(songdata.instr_macros[instr].length)
                else
             else If (songdata.instr_macros[instr].loop_begin > 0) then
                    begin
                      Dec(songdata.instr_macros[instr].loop_begin);
                      While NOT ((songdata.instr_macros[instr].
                                  keyoff_pos > songdata.instr_macros[instr].
                                                       loop_begin+
                                              min0(songdata.instr_macros[instr].
                                                   loop_length-1,0)) or
                                 (songdata.instr_macros[instr].loop_begin = 0) or
                                 (songdata.instr_macros[instr].loop_length = 0) or
                                 (songdata.instr_macros[instr].keyoff_pos = 0)) do
                        Inc(songdata.instr_macros[instr].keyoff_pos);
                    end;

    kCtEND:  If NOT shift_pressed then
               If (songdata.instr_macros[instr].length < 255) then
                 Inc(songdata.instr_macros[instr].length)
               else
             else If (songdata.instr_macros[instr].loop_begin < 255) then
                    begin
                      Inc(songdata.instr_macros[instr].loop_begin);
                      While NOT ((songdata.instr_macros[instr].
                                  keyoff_pos > songdata.instr_macros[instr].
                                                       loop_begin+
                                              min0(songdata.instr_macros[instr].
                                                   loop_length-1,0)) or
                                 (songdata.instr_macros[instr].loop_begin = 0) or
                                 (songdata.instr_macros[instr].loop_length = 0) or
                                 (songdata.instr_macros[instr].keyoff_pos = 0)) do
                        Inc(songdata.instr_macros[instr].keyoff_pos);
                    end;

    kCtPgUP: If NOT shift_pressed then
             else If (songdata.instr_macros[instr].loop_length > 0) then
                    begin
                      Dec(songdata.instr_macros[instr].loop_length);
                      While NOT ((songdata.instr_macros[instr].
                                  keyoff_pos > songdata.instr_macros[instr].
                                                       loop_begin+
                                              min0(songdata.instr_macros[instr].
                                                   loop_length-1,0)) or
                                 (songdata.instr_macros[instr].loop_begin = 0) or
                                 (songdata.instr_macros[instr].loop_length = 0) or
                                 (songdata.instr_macros[instr].keyoff_pos = 0)) do
                        Inc(songdata.instr_macros[instr].keyoff_pos);
                    end;

    kCtPgDN: If NOT shift_pressed then
             else If (songdata.instr_macros[instr].loop_length < 255) then
                    begin
                      Inc(songdata.instr_macros[instr].loop_length);
                      While NOT ((songdata.instr_macros[instr].
                                  keyoff_pos > songdata.instr_macros[instr].
                                                       loop_begin+
                                              min0(songdata.instr_macros[instr].
                                                   loop_length-1,0)) or
                                 (songdata.instr_macros[instr].loop_begin = 0) or
                                 (songdata.instr_macros[instr].loop_length = 0) or
                                 (songdata.instr_macros[instr].keyoff_pos = 0)) do
                        Inc(songdata.instr_macros[instr].keyoff_pos);
                    end;
  end;
end;

procedure _check_arp_general_keys;
begin
  Case is_environment.keystroke of
    kCtHOME:  If NOT shift_pressed then
                If (songdata.macro_table[ptr_arpeggio_table].
                   arpeggio.length > 0) then
                  Dec(songdata.macro_table[ptr_arpeggio_table].
                      arpeggio.length)
                else
             else If (songdata.macro_table[ptr_arpeggio_table].
                      arpeggio.loop_begin > 0) then
                    begin
                      Dec(songdata.macro_table[ptr_arpeggio_table].
                          arpeggio.loop_begin);

                      While NOT ((songdata.macro_table[ptr_arpeggio_table].
                                  arpeggio.keyoff_pos > songdata.macro_table[ptr_arpeggio_table].
                                                        arpeggio.loop_begin+
                                              min0(songdata.macro_table[ptr_arpeggio_table].
                                                   arpeggio.loop_length-1,0)) or
                                 (songdata.macro_table[ptr_arpeggio_table].
                                  arpeggio.loop_begin = 0) or
                                 (songdata.macro_table[ptr_arpeggio_table].
                                  arpeggio.loop_length = 0) or
                                 (songdata.macro_table[ptr_arpeggio_table].
                                  arpeggio.keyoff_pos = 0)) do
                        Inc(songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.keyoff_pos);

                    end;

    kCtEND:  If NOT shift_pressed then
               If (songdata.macro_table[ptr_arpeggio_table].
                   arpeggio.length < 255) then
                 Inc(songdata.macro_table[ptr_arpeggio_table].
                   arpeggio.length)
               else
             else If (songdata.macro_table[ptr_arpeggio_table].
                      arpeggio.loop_begin < 255) then
                    begin
                      Inc(songdata.macro_table[ptr_arpeggio_table].
                          arpeggio.loop_begin);

                      While NOT ((songdata.macro_table[ptr_arpeggio_table].
                                  arpeggio.keyoff_pos > songdata.macro_table[ptr_arpeggio_table].
                                                        arpeggio.loop_begin+
                                              min0(songdata.macro_table[ptr_arpeggio_table].
                                                   arpeggio.loop_length-1,0)) or
                                 (songdata.macro_table[ptr_arpeggio_table].
                                  arpeggio.loop_begin = 0) or
                                 (songdata.macro_table[ptr_arpeggio_table].
                                  arpeggio.loop_length = 0) or
                                 (songdata.macro_table[ptr_arpeggio_table].
                                  arpeggio.keyoff_pos = 0)) do
                        Inc(songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.keyoff_pos);

                    end;

    kCtPgUP: If NOT shift_pressed then
               If (ptr_arpeggio_table > 1) then
                 Dec(ptr_arpeggio_table)
               else
             else If (songdata.macro_table[ptr_arpeggio_table].
                      arpeggio.loop_length > 0) then
                    begin
                      Dec(songdata.macro_table[ptr_arpeggio_table].
                          arpeggio.loop_length);

                      While NOT ((songdata.macro_table[ptr_arpeggio_table].
                                  arpeggio.keyoff_pos > songdata.macro_table[ptr_arpeggio_table].
                                                        arpeggio.loop_begin+
                                              min0(songdata.macro_table[ptr_arpeggio_table].
                                                   arpeggio.loop_length-1,0)) or
                                 (songdata.macro_table[ptr_arpeggio_table].
                                  arpeggio.loop_begin = 0) or
                                 (songdata.macro_table[ptr_arpeggio_table].
                                  arpeggio.loop_length = 0) or
                                 (songdata.macro_table[ptr_arpeggio_table].
                                  arpeggio.keyoff_pos = 0)) do
                        Inc(songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.keyoff_pos);

                    end;

    kCtPgDN: If NOT shift_pressed then
               If (ptr_arpeggio_table < 255) then
                 Inc(ptr_arpeggio_table)
               else
             else If (songdata.macro_table[ptr_arpeggio_table].
                      arpeggio.loop_length < 255) then
                    begin
                      Inc(songdata.macro_table[ptr_arpeggio_table].
                          arpeggio.loop_length);

                      While NOT ((songdata.macro_table[ptr_arpeggio_table].
                                  arpeggio.keyoff_pos > songdata.macro_table[ptr_arpeggio_table].
                                                        arpeggio.loop_begin+
                                              min0(songdata.macro_table[ptr_arpeggio_table].
                                                   arpeggio.loop_length-1,0)) or
                                 (songdata.macro_table[ptr_arpeggio_table].
                                  arpeggio.loop_begin = 0) or
                                 (songdata.macro_table[ptr_arpeggio_table].
                                  arpeggio.loop_length = 0) or
                                 (songdata.macro_table[ptr_arpeggio_table].
                                  arpeggio.keyoff_pos = 0)) do
                        Inc(songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.keyoff_pos);

                    end;

  end;
end;

procedure _check_vib_general_keys;
begin
  Case is_environment.keystroke of
    kCtHOME:  If NOT shift_pressed then
                If (songdata.macro_table[ptr_vibrato_table].
                   vibrato.length > 0) then
                  Dec(songdata.macro_table[ptr_vibrato_table].
                      vibrato.length)
                else
             else If (songdata.macro_table[ptr_vibrato_table].
                      vibrato.loop_begin > 0) then
                    begin
                      Dec(songdata.macro_table[ptr_vibrato_table].
                          vibrato.loop_begin);

                      While NOT ((songdata.macro_table[ptr_vibrato_table].
                                  vibrato.keyoff_pos > songdata.macro_table[ptr_vibrato_table].
                                                       vibrato.loop_begin+
                                              min0(songdata.macro_table[ptr_vibrato_table].
                                                   vibrato.loop_length-1,0)) or
                                 (songdata.macro_table[ptr_vibrato_table].
                                  vibrato.loop_begin = 0) or
                                 (songdata.macro_table[ptr_vibrato_table].
                                  vibrato.loop_length = 0) or
                                 (songdata.macro_table[ptr_vibrato_table].
                                  vibrato.keyoff_pos = 0)) do
                        Inc(songdata.macro_table[ptr_vibrato_table].
                            vibrato.keyoff_pos);

                    end;

    kCtEND:  If NOT shift_pressed then
               If (songdata.macro_table[ptr_vibrato_table].
                   vibrato.length < 255) then
                 Inc(songdata.macro_table[ptr_vibrato_table].
                   vibrato.length)
               else
             else If (songdata.macro_table[ptr_vibrato_table].
                      vibrato.loop_begin < 255) then
                    begin
                      Inc(songdata.macro_table[ptr_vibrato_table].
                          vibrato.loop_begin);

                      While NOT ((songdata.macro_table[ptr_vibrato_table].
                                  vibrato.keyoff_pos > songdata.macro_table[ptr_vibrato_table].
                                                       vibrato.loop_begin+
                                              min0(songdata.macro_table[ptr_vibrato_table].
                                                   vibrato.loop_length-1,0)) or
                                 (songdata.macro_table[ptr_vibrato_table].
                                  vibrato.loop_begin = 0) or
                                 (songdata.macro_table[ptr_vibrato_table].
                                  vibrato.loop_length = 0) or
                                 (songdata.macro_table[ptr_vibrato_table].
                                  vibrato.keyoff_pos = 0)) do
                        Inc(songdata.macro_table[ptr_vibrato_table].
                            vibrato.keyoff_pos);

                    end;

    kCtPgUP: If NOT shift_pressed then
               If (ptr_vibrato_table > 1) then
                 Dec(ptr_vibrato_table)
               else
             else If (songdata.macro_table[ptr_vibrato_table].
                      vibrato.loop_length > 0) then
                    begin
                      Dec(songdata.macro_table[ptr_vibrato_table].
                          vibrato.loop_length);

                      While NOT ((songdata.macro_table[ptr_vibrato_table].
                                  vibrato.keyoff_pos > songdata.macro_table[ptr_vibrato_table].
                                                       vibrato.loop_begin+
                                              min0(songdata.macro_table[ptr_vibrato_table].
                                                   vibrato.loop_length-1,0)) or
                                 (songdata.macro_table[ptr_vibrato_table].
                                  vibrato.loop_begin = 0) or
                                 (songdata.macro_table[ptr_vibrato_table].
                                  vibrato.loop_length = 0) or
                                 (songdata.macro_table[ptr_vibrato_table].
                                  vibrato.keyoff_pos = 0)) do
                        Inc(songdata.macro_table[ptr_vibrato_table].
                            vibrato.keyoff_pos);

                    end;

    kCtPgDN: If NOT shift_pressed then
               If (ptr_vibrato_table < 255) then
                 Inc(ptr_vibrato_table)
               else
             else If (songdata.macro_table[ptr_vibrato_table].
                      vibrato.loop_length < 255) then
                    begin
                      Inc(songdata.macro_table[ptr_vibrato_table].
                          vibrato.loop_length);

                      While NOT ((songdata.macro_table[ptr_vibrato_table].
                                  vibrato.keyoff_pos > songdata.macro_table[ptr_vibrato_table].
                                                       vibrato.loop_begin+
                                              min0(songdata.macro_table[ptr_vibrato_table].
                                                   vibrato.loop_length-1,0)) or
                                 (songdata.macro_table[ptr_vibrato_table].
                                  vibrato.loop_begin = 0) or
                                 (songdata.macro_table[ptr_vibrato_table].
                                  vibrato.loop_length = 0) or
                                 (songdata.macro_table[ptr_vibrato_table].
                                  vibrato.keyoff_pos = 0)) do
                        Inc(songdata.macro_table[ptr_vibrato_table].
                            vibrato.keyoff_pos);

                    end;
  end;
end;

label _jmp1,_jmp2,_end2;

begin { MACRO_EDITOR }
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_EDITOR';
{$ENDIF}

  _arp_vib_mode := arp_vib_mode;
  If (program_screen_mode in [0,3,4,5]) then
    begin
       window_area_inc_x := 0;
       window_area_inc_y := 0;
    end
  else begin
         If NOT arp_vib_mode then window_area_inc_x := 10
         else window_area_inc_x := 0;
         window_area_inc_y := 10;
       end;

  call_pickup_proc := FALSE;
  _source_ins := instrum_page;
  call_pickup_proc2 := FALSE;
  _source_ins2 := instrum_page;

_jmp1:
  If NOT arp_vib_mode then
    begin
      ptr_arpeggio_table := songdata.instr_macros[instr].arpeggio_table;
      ptr_vibrato_table := songdata.instr_macros[instr].vibrato_table;
    end
  else begin
         ptr_arpeggio_table := arpvib_arpeggio_table;
         ptr_vibrato_table := arpvib_vibrato_table;
       end;

  pos := _macro_editor__pos[arp_vib_mode];
  If arp_vib_mode and (pos < 8) then pos := 8
  else If NOT arp_vib_mode and
          (((ptr_arpeggio_table = 0) and (pos in [8..13])) or
           ((ptr_vibrato_table = 0) and (pos in [14..20]))) then
          pos := 1;

  fmreg_hpos := _macro_editor__fmreg_hpos[arp_vib_mode];
  fmreg_page := _macro_editor__fmreg_page[arp_vib_mode];
  fmreg_left_margin := _macro_editor__fmreg_left_margin[arp_vib_mode];
  fmreg_cursor_pos := _macro_editor__fmreg_cursor_pos[arp_vib_mode];
  arpeggio_page := _macro_editor__arpeggio_page[arp_vib_mode];
  vibrato_hpos := _macro_editor__vibrato_hpos[arp_vib_mode];
  vibrato_page := _macro_editor__vibrato_page[arp_vib_mode];

  If _force_program_quit then EXIT;

  ScreenMemCopy(screen_ptr,ptr_screen_backup);
  HideCursor;

  For temp := 1 to 255 do
    begin
      temp_marks[temp] := songdata.instr_names[temp][1];
      songdata.instr_names[temp][1] := ' ';
    end;

  songdata_crc := Update32(songdata,SizeOf(songdata),0);
  For temp := 1 to 255 do
    songdata.instr_names[temp][1] := temp_marks[temp];

  ScreenMemCopy(screen_ptr,ptr_temp_screen);
  centered_frame_vdest := ptr_temp_screen;

  If NOT arp_vib_mode then
    centered_frame(xstart,ystart,81+window_area_inc_x,24+window_area_inc_y,
                   ' iNSTRUMENT MACRO EDiTOR (iNS_  ) ',
                   macro_background+dialog_border,
                   macro_background+dialog_title,
                   double)
  else
    centered_frame(xstart,ystart,81+window_area_inc_x,24+window_area_inc_y,
                   ' ARPEGGiO/ViBRATO MACRO EDiTOR (iNS_  ) ',
                   macro_background+dialog_border,
                   macro_background+dialog_title,
                   double);

  _pip_xloc := xstart+30+(window_area_inc_x DIV 2);
  _pip_yloc := ystart+2;
  _pip_dest := ptr_temp_screen;

  move_to_screen_data := ptr_temp_screen;
  move_to_screen_area[1] := xstart;
  move_to_screen_area[2] := ystart;
  move_to_screen_area[3] := xstart+81+2+window_area_inc_x;
  move_to_screen_area[4] := ystart+24+1+window_area_inc_y;
  refresh;

  move_to_screen_area[1] := xstart+1;
  move_to_screen_area[2] := ystart+1;
  move_to_screen_area[3] := xstart+80+window_area_inc_x;
  move_to_screen_area[4] := ystart+24+window_area_inc_y;

  If (pos = 1) then GotoXY(xstart+17,ystart+4);
  ThinCursor;
  centered_frame_vdest := screen_ptr;

  Move(is_setting.terminate_keys,old_keys,SizeOf(old_keys));
  Move(new_keys,is_setting.terminate_keys,SizeOf(new_keys));

_jmp2:
  If NOT arp_vib_mode then
    begin
      songdata.instr_macros[instr].arpeggio_table := ptr_arpeggio_table;
      songdata.instr_macros[instr].vibrato_table := ptr_vibrato_table;
    end;

  If (instr <> current_inst) then
    instr := current_inst;

  If NOT arp_vib_mode then
    begin
      ptr_arpeggio_table := songdata.instr_macros[instr].arpeggio_table;
      ptr_vibrato_table := songdata.instr_macros[instr].vibrato_table;
    end;

  If arp_vib_mode and (pos < 8) then pos := 8
  else If NOT arp_vib_mode and
          (((ptr_arpeggio_table = 0) and (pos in [8..13])) or
           ((ptr_vibrato_table = 0) and (pos in [14..20]))) then
          pos := 1;

  If NOT arp_vib_mode then
    ShowStr(centered_frame_vdest,xstart+54+(window_area_inc_x DIV 2),ystart,
            byte2hex(instr),macro_background+dialog_title)
  else
    ShowStr(centered_frame_vdest,xstart+57+(window_area_inc_x DIV 2),ystart,
            byte2hex(instr),macro_background+dialog_title);

  If NOT _force_program_quit then
    Repeat
      refresh;
      is_setting.append_enabled := TRUE;
      is_environment.locate_pos := 1;

      Case pos of

    (* FM_op_table table - pos: 1..7 *)

        1: begin
             is_setting.character_set := ['0'..'9','a'..'f','A'..'F'];
             Repeat
               temps := InputStr(byte2hex(songdata.instr_macros[instr].length),
                                 xstart+17,ystart+4,
                                 2,2,
                                 macro_input_bckg+macro_input,
                                 macro_def_bckg+macro_def);
             until (is_environment.keystroke = kESC) or
                   ((Str2num(temps,16) >= 0) and (Str2num(temps,16) <= 255));

             songdata.instr_macros[instr].length := Str2num(temps,16);
             Case is_environment.keystroke of
               kCHplus,
               kNPplus: If (songdata.instr_macros[instr].length < 255) then
                          Inc(songdata.instr_macros[instr].length);
               kCHmins,
               kNPmins: If (songdata.instr_macros[instr].length > 0) then
                          Dec(songdata.instr_macros[instr].length);
             end;

             If (is_environment.keystroke = kENTER) or
                (is_environment.keystroke = kTAB) or
                (is_environment.keystroke = kDOWN) then pos := 2
             else If (is_environment.keystroke = kUP) then pos := 7
                  else If (is_environment.keystroke = kShTAB) then
                         If (ptr_vibrato_table <> 0) then pos := 20
                         else If (ptr_arpeggio_table <> 0) then pos := 13
                              else pos := 7;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_fmreg_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If (ptr_vibrato_table <> 0) then pos := 14
                        else If (ptr_arpeggio_table <> 0) then pos := 8;

               kCtRGHT: If (ptr_arpeggio_table <> 0) then pos := 8
                        else If (ptr_vibrato_table <> 0) then pos := 14;

               kCtrlC:  begin
                          clipboard.object_type := objMacroTable;
                          clipboard.mcrtab_type := mttFM_reg_table;
                          copy_object;
                        end;
               kCtrlV,
               kAltP:   paste_object;
             end;
           end;

        2: begin
             is_setting.character_set := ['0'..'9','a'..'f','A'..'F'];
             Repeat
               temps := InputStr(byte2hex(songdata.instr_macros[instr].loop_begin),
                                 xstart+17,ystart+5,
                                 2,2,
                                 macro_input_bckg+macro_input,
                                 macro_def_bckg+macro_def);
             until (is_environment.keystroke = kESC) or
                   ((Str2num(temps,16) >= 0) and (Str2num(temps,16) <= 255));

             songdata.instr_macros[instr].loop_begin := Str2num(temps,16);
             Case is_environment.keystroke of
               kCHplus,
               kNPplus: If (songdata.instr_macros[instr].loop_begin < 255) then
                          Inc(songdata.instr_macros[instr].loop_begin);
               kCHmins,
               kNPmins: If (songdata.instr_macros[instr].loop_begin > 0) then
                          Dec(songdata.instr_macros[instr].loop_begin);
             end;

             While NOT ((songdata.instr_macros[instr].keyoff_pos > songdata.instr_macros[instr].loop_begin+
                                     min0(songdata.instr_macros[instr].loop_length-1,0)) or
                        (songdata.instr_macros[instr].loop_begin = 0) or
                        (songdata.instr_macros[instr].loop_length = 0) or
                        (songdata.instr_macros[instr].keyoff_pos = 0)) do
               Inc(songdata.instr_macros[instr].keyoff_pos);

             If (is_environment.keystroke = kENTER) or
                (is_environment.keystroke = kTAB) or
                (is_environment.keystroke = kDOWN) then pos := 3
             else If (is_environment.keystroke = kUP) or
                     (is_environment.keystroke = kShTAB) then pos := 1;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_fmreg_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If (ptr_vibrato_table <> 0) then pos := 17
                        else If (ptr_arpeggio_table <> 0) then pos := 10;

               kCtRGHT: If (ptr_arpeggio_table <> 0) then pos := 10
                        else If (ptr_vibrato_table <> 0) then pos := 17;

               kCtrlC:  begin
                          clipboard.object_type := objMacroTable;
                          clipboard.mcrtab_type := mttFM_reg_table;
                          copy_object;
                        end;
               kCtrlV,
               kAltP:   paste_object;
             end;
           end;

        3: begin
             is_setting.character_set := ['0'..'9','a'..'f','A'..'F'];
             Repeat
               temps := InputStr(byte2hex(songdata.instr_macros[instr].loop_length),
                                 xstart+17,ystart+6,
                                 2,2,
                                 macro_input_bckg+macro_input,
                                 macro_def_bckg+macro_def);
             until (is_environment.keystroke = kESC) or
                   ((Str2num(temps,16) >= 0) and (Str2num(temps,16) <= 255));

             songdata.instr_macros[instr].loop_length := Str2num(temps,16);
             Case is_environment.keystroke of
               kCHplus,
               kNPplus: If (songdata.instr_macros[instr].loop_length < 255) then
                          Inc(songdata.instr_macros[instr].loop_length);
               kCHmins,
               kNPmins: If (songdata.instr_macros[instr].loop_length > 0) then
                          Dec(songdata.instr_macros[instr].loop_length);
             end;

             While NOT ((songdata.instr_macros[instr].keyoff_pos > songdata.instr_macros[instr].loop_begin+
                                     min0(songdata.instr_macros[instr].loop_length-1,0)) or
                        (songdata.instr_macros[instr].loop_begin = 0) or
                        (songdata.instr_macros[instr].loop_length = 0) or
                        (songdata.instr_macros[instr].keyoff_pos = 0)) do
               Inc(songdata.instr_macros[instr].keyoff_pos);

             If (is_environment.keystroke = kENTER) or
                (is_environment.keystroke = kTAB) or
                (is_environment.keystroke = kDOWN) then pos := 4
             else If (is_environment.keystroke = kUP) or
                     (is_environment.keystroke = kShTAB) then pos := 2;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_fmreg_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If (ptr_vibrato_table <> 0) then pos := 18
                        else If (ptr_arpeggio_table <> 0) then pos := 11;

               kCtRGHT: If (ptr_arpeggio_table <> 0) then pos := 11
                        else If (ptr_vibrato_table <> 0) then pos := 18;

               kCtrlC:  begin
                          clipboard.object_type := objMacroTable;
                          clipboard.mcrtab_type := mttFM_reg_table;
                          copy_object;
                        end;
               kCtrlV,
               kAltP:   paste_object;
             end;
           end;

        4: begin
             is_setting.character_set := ['0'..'9','a'..'f','A'..'F'];
             Repeat
               temps := InputStr(byte2hex(songdata.instr_macros[instr].keyoff_pos),
                                 xstart+17,ystart+7,
                                 2,2,
                                 macro_input_bckg+macro_input,
                                 macro_def_bckg+macro_def);
             until (is_environment.keystroke = kESC) or
                   (Str2num(temps,16) >= 0) and (Str2num(temps,16) <= 255) and
                   (Str2num(temps,16) > songdata.instr_macros[instr].loop_begin+
                                        min0(songdata.instr_macros[instr].loop_length-1,0)) or
                   (songdata.instr_macros[instr].loop_begin = 0) or
                   (songdata.instr_macros[instr].loop_length = 0) or
                   (Str2num(temps,16) = 0);

             songdata.instr_macros[instr].keyoff_pos := Str2num(temps,16);
             Case is_environment.keystroke of
               kCHplus,
               kNPplus: If (songdata.instr_macros[instr].loop_begin = 0) or
                           (songdata.instr_macros[instr].loop_length = 0) or
                           (songdata.instr_macros[instr].keyoff_pos <> 0) then
                          If (songdata.instr_macros[instr].keyoff_pos < 255) then
                            Inc(songdata.instr_macros[instr].keyoff_pos)
                          else
                        else If (songdata.instr_macros[instr].loop_begin+
                                 songdata.instr_macros[instr].loop_length <= 255) then
                               songdata.instr_macros[instr].keyoff_pos :=
                                 songdata.instr_macros[instr].loop_begin+
                                 songdata.instr_macros[instr].loop_length;
               kCHmins,
               kNPmins: If (min0(songdata.instr_macros[instr].keyoff_pos-1,0) > songdata.instr_macros[instr].loop_begin+
                              min0(songdata.instr_macros[instr].loop_length-1,0)) or
                           ((songdata.instr_macros[instr].keyoff_pos > 0) and
                           ((songdata.instr_macros[instr].loop_begin = 0) or
                            (songdata.instr_macros[instr].loop_length = 0))) then
                          Dec(songdata.instr_macros[instr].keyoff_pos);
             end;

             If (is_environment.keystroke = kENTER) or
                (is_environment.keystroke = kTAB) or
                (is_environment.keystroke = kDOWN) then pos := 5
             else If (is_environment.keystroke = kUP) or
                     (is_environment.keystroke = kShTAB) then pos := 3;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_fmreg_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If (ptr_vibrato_table <> 0) then pos := 19
                        else If (ptr_arpeggio_table <> 0) then pos := 12;

               kCtRGHT: If (ptr_arpeggio_table <> 0) then pos := 12
                        else If (ptr_vibrato_table <> 0) then pos := 19;

               kCtrlC:  begin
                          clipboard.object_type := objMacroTable;
                          clipboard.mcrtab_type := mttFM_reg_table;
                          copy_object;
                        end;
               kCtrlV,
               kAltP:   paste_object;
             end;
           end;

        5: begin
             is_setting.character_set := ['0'..'9','a'..'f','A'..'F'];
             Repeat
               temps := InputStr(byte2hex(ptr_arpeggio_table),
                                 xstart+17,ystart+8,
                                 2,2,
                                 macro_input_bckg+macro_input,
                                 macro_def_bckg+macro_def);
             until (is_environment.keystroke = kESC) or
                   ((Str2num(temps,16) >= 0) and (Str2num(temps,16) <= 255));

             ptr_arpeggio_table := Str2num(temps,16);
             Case is_environment.keystroke of
               kCHplus,
               kNPplus: If (ptr_arpeggio_table < 255) then
                          Inc(ptr_arpeggio_table);
               kCHmins,
               kNPmins: If (ptr_arpeggio_table > 0) then
                          Dec(ptr_arpeggio_table);
             end;

             If (is_environment.keystroke = kENTER) or
                (is_environment.keystroke = kTAB) or
                (is_environment.keystroke = kDOWN) then pos := 6
             else If (is_environment.keystroke = kUP) or
                     (is_environment.keystroke = kShTAB) then pos := 4;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_fmreg_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If (ptr_vibrato_table <> 0) then pos := 14
                        else If (ptr_arpeggio_table <> 0) then pos := 8;

               kCtRGHT: If (ptr_arpeggio_table <> 0) then pos := 8
                        else If (ptr_vibrato_table <> 0) then pos := 14;
             end;
           end;

        6: begin
             is_setting.character_set := ['0'..'9','a'..'f','A'..'F'];
             Repeat
               temps := InputStr(byte2hex(ptr_vibrato_table),
                                 xstart+17,ystart+9,
                                 2,2,
                                 macro_input_bckg+macro_input,
                                 macro_def_bckg+macro_def);
             until (is_environment.keystroke = kESC) or
                   ((Str2num(temps,16) >= 0) and (Str2num(temps,16) <= 255));

             ptr_vibrato_table := Str2num(temps,16);
             Case is_environment.keystroke of
               kCHplus,
               kNPplus: If (ptr_vibrato_table < 255) then
                          Inc(ptr_vibrato_table);
               kCHmins,
               kNPmins: If (ptr_vibrato_table > 0) then
                          Dec(ptr_vibrato_table);
             end;

             If (is_environment.keystroke = kENTER) or
                (is_environment.keystroke = kTAB) or
                (is_environment.keystroke = kDOWN) then pos := 7
             else If (is_environment.keystroke = kUP) or
                     (is_environment.keystroke = kShTAB) then pos := 5;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_fmreg_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If (ptr_vibrato_table <> 0) then pos := 14
                        else If (ptr_arpeggio_table <> 0) then pos := 8;

               kCtRGHT: If (ptr_arpeggio_table <> 0) then pos := 8
                        else If (ptr_vibrato_table <> 0) then pos := 14;

               kCtrlC:  begin
                          clipboard.object_type := objMacroTable;
                          clipboard.mcrtab_type := mttFM_reg_table;
                          copy_object;
                        end;
               kCtrlV,
               kAltP:   paste_object;
             end;
           end;

        7: begin
             GotoXY(xstart+10+fmreg_cursor_pos-1,ystart+16+(window_area_inc_y DIV 2));
             is_environment.keystroke := getkey;

             If (HI(is_environment.keystroke) = HI(kSlashR)) then
               With songdata.instr_macros[instr].data[fmreg_page] do
                 begin
                   nope := TRUE;
                   Case fmreg_hpos of
                     10: fm_data.AM_VIB_EG_modulator :=
                         fm_data.AM_VIB_EG_modulator XOR $80;
                     11: fm_data.AM_VIB_EG_modulator :=
                         fm_data.AM_VIB_EG_modulator XOR $40;
                     12: fm_data.AM_VIB_EG_modulator :=
                         fm_data.AM_VIB_EG_modulator XOR $10;
                     13: fm_data.AM_VIB_EG_modulator :=
                         fm_data.AM_VIB_EG_modulator XOR $20;

                     23: fm_data.AM_VIB_EG_carrier :=
                         fm_data.AM_VIB_EG_carrier XOR $80;
                     24: fm_data.AM_VIB_EG_carrier :=
                         fm_data.AM_VIB_EG_carrier XOR $40;
                     25: fm_data.AM_VIB_EG_carrier :=
                         fm_data.AM_VIB_EG_carrier XOR $10;
                     26: fm_data.AM_VIB_EG_carrier :=
                         fm_data.AM_VIB_EG_carrier XOR $20;

                     33: begin
                           nope := FALSE;
                           Case panning of
                             0: panning := 2;
                             1: panning := 0;
                             2: panning := 1;
                           end;
                         end
                     else
                       nope := FALSE;
                   end;

                   If nope then
                     If (fmreg_page < 255) then Inc(fmreg_page)
                     else If cycle_pattern then fmreg_page := 1;
                 end;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_fmreg_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If NOT shift_pressed then
                          If (ptr_vibrato_table <> 0) then pos := 20
                          else If (ptr_arpeggio_table <> 0) then pos := 13
                               else
                        else If (fmreg_page > songdata.instr_macros[instr].length) then
                               fmreg_page := min(1,songdata.instr_macros[instr].length)
                             else fmreg_page := 1;

               kCtRGHT: If NOT shift_pressed then
                          If (ptr_arpeggio_table <> 0) then pos := 13
                          else If (ptr_vibrato_table <> 0) then pos := 20
                               else
                        else If (fmreg_page < songdata.instr_macros[instr].length) then
                               fmreg_page := min(1,songdata.instr_macros[instr].length)
                             else fmreg_page := 255;

               kUP: If (fmreg_page > 1) then Dec(fmreg_page)
                    else If cycle_pattern then fmreg_page := 255;

               kDOWN: If (fmreg_page < 255) then Inc(fmreg_page)
                      else If cycle_pattern then fmreg_page := 1;

               kPgUP: If (fmreg_page > 16) then Dec(fmreg_page,16)
                      else fmreg_page := 1;

               kPgDOWN: If (fmreg_page+16 < 255) then Inc(fmreg_page,16)
                        else fmreg_page := 255;

               kHOME: If NOT shift_pressed then fmreg_page := 1
                      else begin
                             fmreg_hpos := 1;
                             fmreg_cursor_pos := 1;
                             fmreg_left_margin := 1;
                           end;

               kEND: If NOT shift_pressed then fmreg_page := 255
                     else begin
                            fmreg_hpos := 35;
                            fmreg_cursor_pos := max(57,31+window_area_inc_x);
                            fmreg_left_margin := min(pos5[fmreg_hpos]-(31+window_area_inc_x)+1,1);
                          end;

               kNPHOME: If shift_pressed then
                          begin
                            fmreg_hpos := 1;
                            fmreg_cursor_pos := 1;
                            fmreg_left_margin := 1;
                          end;

               kNPEND: If shift_pressed then
                         begin
                           fmreg_hpos := 35;
                           fmreg_cursor_pos := max(57,31+window_area_inc_x);
                           fmreg_left_margin := min(pos5[fmreg_hpos]-(31+window_area_inc_x)+1,1);
                         end;

               kLEFT: If (fmreg_hpos > 1) then
                        begin
                          Dec(fmreg_hpos);
                          _scroll_cur_left;
                        end
                      else If cycle_pattern then
                             begin
                               fmreg_hpos := 35;
                               fmreg_cursor_pos := max(57,31+window_area_inc_x);
                               fmreg_left_margin := min(pos5[fmreg_hpos]-(31+window_area_inc_x)+1,1);
                             end;

               kRIGHT: If (fmreg_hpos < 35) then
                         begin
                           Inc(fmreg_hpos);
                           _scroll_cur_right;
                         end
                       else If cycle_pattern then
                              begin
                                fmreg_hpos := 1;
                                fmreg_cursor_pos := 1;
                                fmreg_left_margin := 1;
                              end;

               kTAB: If (ptr_arpeggio_table <> 0) then pos := 8
                     else If (ptr_vibrato_table <> 0) then pos := 14
                            else pos := 1;

               kShTAB: pos := 6;

               kENTER: If NOT shift_pressed then
                         begin
                           If (ptr_arpeggio_table <> 0) then pos := 8
                           else If (ptr_vibrato_table <> 0) then pos := 14
                                else pos := 1;
                         end
                       else call_pickup_proc2 := TRUE;

               kCtrlC: begin
                         If NOT shift_pressed then clipboard.object_type := objMacroTableLine
                         else clipboard.object_type := objMacroTableColumn;
                         clipboard.mcrtab_type := mttFM_reg_table;
                         copy_object;
                       end;
               kCtrlV,
               kAltP: begin
                        paste_object;
                        If (clipboard.object_type = objMacroTableLine) and
                           (clipboard.mcrtab_type = mttFM_reg_table) then
                          If (fmreg_page < 255) then Inc(fmreg_page)
                          else If cycle_pattern then fmreg_page := 1;
                      end;

               kCtrlN: begin
                         songdata.instr_macros[instr].data[fmreg_page].fm_data.
                           FEEDBACK_FM :=
                         songdata.instr_macros[instr].data[fmreg_page].fm_data.
                           FEEDBACK_FM XOR $80;
                         If (fmreg_page < 255) then Inc(fmreg_page)
                         else If cycle_pattern then fmreg_page := 1;
                       end;

               kAltN:  If ctrl_pressed then
                         For temp := 1 to 255 do
                            songdata.instr_macros[instr].data[temp].fm_data.
                              FEEDBACK_FM :=
                            songdata.instr_macros[instr].data[temp].fm_data.
                              FEEDBACK_FM AND $7f;

               kCtENTR: If NOT shift_pressed then
                          begin
                            temp := songdata.instr_macros[instr].data[fmreg_page].
                                    fm_data.FEEDBACK_FM;
                            songdata.instr_macros[instr].data[fmreg_page].fm_data :=
                              songdata.instr_data[instr].fm_data;
                            songdata.instr_macros[instr].data[fmreg_page].
                            fm_data.FEEDBACK_FM := temp AND $0c0+
                              songdata.instr_data[instr].fm_data.FEEDBACK_FM;

                            songdata.instr_macros[instr].data[fmreg_page].panning :=
                              songdata.instr_data[instr].panning;
                            songdata.instr_macros[instr].data[fmreg_page].duration :=
                              min(songdata.instr_macros[instr].data[fmreg_page].duration,1);

                            With songdata.instr_macros[instr].data[fmreg_page].fm_data do
                              begin
                                KSL_VOLUM_modulator := KSL_VOLUM_modulator AND $c0+
                                                       63-KSL_VOLUM_modulator AND $3f;
                                KSL_VOLUM_carrier := KSL_VOLUM_carrier AND $c0+
                                                     63-KSL_VOLUM_carrier AND $3f;
                              end;

                            If (fmreg_page < 255) then Inc(fmreg_page)
                            else If cycle_pattern then fmreg_page := 1;
                          end
                        else call_pickup_proc := TRUE;

               kINSERT: begin
                          For temp := 255-1 downto fmreg_page do
                            begin
                              songdata.instr_macros[instr].data[SUCC(temp)] :=
                                songdata.instr_macros[instr].data[temp]
                            end;
                          FillChar(songdata.instr_macros[instr].data[fmreg_page],
                                   SizeOf(songdata.instr_macros[instr].data[fmreg_page]),0);
                        end;

               kDELETE: begin
                          For temp := fmreg_page to 255-1 do
                            begin
                              songdata.instr_macros[instr].data[temp] :=
                                songdata.instr_macros[instr].data[SUCC(temp)]
                            end;
                          FillChar(songdata.instr_macros[instr].data[255],
                                   SizeOf(songdata.instr_macros[instr].data[255]),0);
                        end;
               kCHplus,
               kNPplus: With songdata.instr_macros[instr].data[fmreg_page] do
                          Case fmreg_hpos of
                            1: fm_data.ATTCK_DEC_modulator :=
                               _inc(fm_data.ATTCK_DEC_modulator SHR 4,15) SHL 4+
                               fm_data.ATTCK_DEC_modulator AND $0f;
                            2: fm_data.ATTCK_DEC_modulator :=
                               fm_data.ATTCK_DEC_modulator AND $0f0+
                               _inc(fm_data.ATTCK_DEC_modulator AND $0f,15);
                            3: fm_data.SUSTN_REL_modulator :=
                               _inc(fm_data.SUSTN_REL_modulator SHR 4,15) SHL 4+
                               fm_data.SUSTN_REL_modulator AND $0f;
                            4: fm_data.SUSTN_REL_modulator :=
                               fm_data.SUSTN_REL_modulator AND $0f0+
                               _inc(fm_data.SUSTN_REL_modulator AND $0f,15);
                            5: fm_data.WAVEFORM_modulator :=
                               _inc(fm_data.WAVEFORM_modulator,7);
                            6,
                            7: fm_data.KSL_VOLUM_modulator :=
                               fm_data.KSL_VOLUM_modulator AND $0c0+
                               _inc(fm_data.KSL_VOLUM_modulator AND $3f,63);
                            8: fm_data.KSL_VOLUM_modulator :=
                               fm_data.KSL_VOLUM_modulator AND $3f+
                               _inc(fm_data.KSL_VOLUM_modulator SHR 6,3) SHL 6;
                            9: fm_data.AM_VIB_EG_modulator :=
                               fm_data.AM_VIB_EG_modulator AND $0f0+
                               _inc(fm_data.AM_VIB_EG_modulator AND $0f,15);
                           10: fm_data.AM_VIB_EG_modulator :=
                               fm_data.AM_VIB_EG_modulator AND $7f+
                               _inc(fm_data.AM_VIB_EG_modulator SHR 7,1) SHL 7;
                           11: fm_data.AM_VIB_EG_modulator :=
                               fm_data.AM_VIB_EG_modulator AND $0bf+
                               _inc(fm_data.AM_VIB_EG_modulator SHR 6 AND 1,1) SHL 6;
                           12: fm_data.AM_VIB_EG_modulator :=
                               fm_data.AM_VIB_EG_modulator AND $0ef+
                               _inc(fm_data.AM_VIB_EG_modulator SHR 4 AND 1,1) SHL 4;
                           13: fm_data.AM_VIB_EG_modulator :=
                               fm_data.AM_VIB_EG_modulator AND $0df+
                               _inc(fm_data.AM_VIB_EG_modulator SHR 5 AND 1,1) SHL 5;
                           14: fm_data.ATTCK_DEC_carrier :=
                               _inc(fm_data.ATTCK_DEC_carrier SHR 4,15) SHL 4+
                               fm_data.ATTCK_DEC_carrier AND $0f;
                           15: fm_data.ATTCK_DEC_carrier :=
                               fm_data.ATTCK_DEC_carrier AND $0f0+
                               _inc(fm_data.ATTCK_DEC_carrier AND $0f,15);
                           16: fm_data.SUSTN_REL_carrier :=
                               _inc(fm_data.SUSTN_REL_carrier SHR 4,15) SHL 4+
                               fm_data.SUSTN_REL_carrier AND $0f;
                           17: fm_data.SUSTN_REL_carrier :=
                               fm_data.SUSTN_REL_carrier AND $0f0+
                               _inc(fm_data.SUSTN_REL_carrier AND $0f,15);
                           18: fm_data.WAVEFORM_carrier :=
                               _inc(fm_data.WAVEFORM_carrier,7);
                           19,
                           20: fm_data.KSL_VOLUM_carrier :=
                               fm_data.KSL_VOLUM_carrier AND $0c0+
                               _inc(fm_data.KSL_VOLUM_carrier AND $3f,63);
                           21: fm_data.KSL_VOLUM_carrier :=
                               fm_data.KSL_VOLUM_carrier AND $3f+
                               _inc(fm_data.KSL_VOLUM_carrier SHR 6,3) SHL 6;
                           22: fm_data.AM_VIB_EG_carrier :=
                               fm_data.AM_VIB_EG_carrier AND $0f0+
                               _inc(fm_data.AM_VIB_EG_carrier AND $0f,15);
                           23: fm_data.AM_VIB_EG_carrier :=
                               fm_data.AM_VIB_EG_carrier AND $7f+
                               _inc(fm_data.AM_VIB_EG_carrier SHR 7,1) SHL 7;
                           24: fm_data.AM_VIB_EG_carrier :=
                               fm_data.AM_VIB_EG_carrier AND $0bf+
                               _inc(fm_data.AM_VIB_EG_carrier SHR 6 AND 1,1) SHL 6;
                           25: fm_data.AM_VIB_EG_carrier :=
                               fm_data.AM_VIB_EG_carrier AND $0ef+
                               _inc(fm_data.AM_VIB_EG_carrier SHR 4 AND 1,1) SHL 4;
                           26: fm_data.AM_VIB_EG_carrier :=
                               fm_data.AM_VIB_EG_carrier AND $0df+
                               _inc(fm_data.AM_VIB_EG_carrier SHR 5 AND 1,1) SHL 5;
                           27: fm_data.FEEDBACK_FM :=
                               fm_data.FEEDBACK_FM AND $0fe+
                               _inc(fm_data.FEEDBACK_FM AND 1,1);
                           28: fm_data.FEEDBACK_FM :=
                               fm_data.FEEDBACK_FM AND 1+
                               _inc(fm_data.FEEDBACK_FM SHR 1,7) SHL 1;

                           29,30,31,
                           32: freq_slide :=
                               _inc(freq_slide,1023);
                           33: Case panning of
                                 0: panning := 2;
                                 1: panning := 0;
                               end;
                           34,
                           35: duration :=
                               _inc(duration,255);
                          end;
               kCHmins,
               kNPmins: With songdata.instr_macros[instr].data[fmreg_page] do
                          Case fmreg_hpos of
                            1: fm_data.ATTCK_DEC_modulator :=
                               _dec(fm_data.ATTCK_DEC_modulator SHR 4,0) SHL 4+
                               fm_data.ATTCK_DEC_modulator AND $0f;
                            2: fm_data.ATTCK_DEC_modulator :=
                               fm_data.ATTCK_DEC_modulator AND $0f0+
                               _dec(fm_data.ATTCK_DEC_modulator AND $0f,0);
                            3: fm_data.SUSTN_REL_modulator :=
                               _dec(fm_data.SUSTN_REL_modulator SHR 4,0) SHL 4+
                               fm_data.SUSTN_REL_modulator AND $0f;
                            4: fm_data.SUSTN_REL_modulator :=
                               fm_data.SUSTN_REL_modulator AND $0f0+
                               _dec(fm_data.SUSTN_REL_modulator AND $0f,0);
                            5: fm_data.WAVEFORM_modulator :=
                               _dec(fm_data.WAVEFORM_modulator,0);
                            6,
                            7: fm_data.KSL_VOLUM_modulator :=
                               fm_data.KSL_VOLUM_modulator AND $0c0+
                               _dec(fm_data.KSL_VOLUM_modulator AND $3f,0);
                            8: fm_data.KSL_VOLUM_modulator :=
                               fm_data.KSL_VOLUM_modulator AND $3f+
                               _dec(fm_data.KSL_VOLUM_modulator SHR 6,0) SHL 6;
                            9: fm_data.AM_VIB_EG_modulator :=
                               fm_data.AM_VIB_EG_modulator AND $0f0+
                               _dec(fm_data.AM_VIB_EG_modulator AND $0f,0);
                           10: fm_data.AM_VIB_EG_modulator :=
                               fm_data.AM_VIB_EG_modulator AND $7f+
                               _dec(fm_data.AM_VIB_EG_modulator SHR 7,0) SHL 7;
                           11: fm_data.AM_VIB_EG_modulator :=
                               fm_data.AM_VIB_EG_modulator AND $0bf+
                               _dec(fm_data.AM_VIB_EG_modulator SHR 6 AND 1,0) SHL 6;
                           12: fm_data.AM_VIB_EG_modulator :=
                               fm_data.AM_VIB_EG_modulator AND $0ef+
                               _dec(fm_data.AM_VIB_EG_modulator SHR 4 AND 1,0) SHL 4;
                           13: fm_data.AM_VIB_EG_modulator :=
                               fm_data.AM_VIB_EG_modulator AND $0df+
                               _dec(fm_data.AM_VIB_EG_modulator SHR 5 AND 1,0) SHL 5;
                           14: fm_data.ATTCK_DEC_carrier :=
                               _dec(fm_data.ATTCK_DEC_carrier SHR 4,0) SHL 4+
                               fm_data.ATTCK_DEC_carrier AND $0f;
                           15: fm_data.ATTCK_DEC_carrier :=
                               fm_data.ATTCK_DEC_carrier AND $0f0+
                               _dec(fm_data.ATTCK_DEC_carrier AND $0f,0);
                           16: fm_data.SUSTN_REL_carrier :=
                               _dec(fm_data.SUSTN_REL_carrier SHR 4,0) SHL 4+
                               fm_data.SUSTN_REL_carrier AND $0f;
                           17: fm_data.SUSTN_REL_carrier :=
                               fm_data.SUSTN_REL_carrier AND $0f0+
                               _dec(fm_data.SUSTN_REL_carrier AND $0f,0);
                           18: fm_data.WAVEFORM_carrier :=
                               _dec(fm_data.WAVEFORM_carrier,0);
                           19,
                           20: fm_data.KSL_VOLUM_carrier :=
                               fm_data.KSL_VOLUM_carrier AND $0c0+
                               _dec(fm_data.KSL_VOLUM_carrier AND $3f,0);
                           21: fm_data.KSL_VOLUM_carrier :=
                               fm_data.KSL_VOLUM_carrier AND $3f+
                               _dec(fm_data.KSL_VOLUM_carrier SHR 6,0) SHL 6;
                           22: fm_data.AM_VIB_EG_carrier :=
                               fm_data.AM_VIB_EG_carrier AND $0f0+
                               _dec(fm_data.AM_VIB_EG_carrier AND $0f,0);
                           23: fm_data.AM_VIB_EG_carrier :=
                               fm_data.AM_VIB_EG_carrier AND $7f+
                               _dec(fm_data.AM_VIB_EG_carrier SHR 7,0) SHL 7;
                           24: fm_data.AM_VIB_EG_carrier :=
                               fm_data.AM_VIB_EG_carrier AND $0bf+
                               _dec(fm_data.AM_VIB_EG_carrier SHR 6 AND 1,0) SHL 6;
                           25: fm_data.AM_VIB_EG_carrier :=
                               fm_data.AM_VIB_EG_carrier AND $0ef+
                               _dec(fm_data.AM_VIB_EG_carrier SHR 4 AND 1,0) SHL 4;
                           26: fm_data.AM_VIB_EG_carrier :=
                               fm_data.AM_VIB_EG_carrier AND $0df+
                               _dec(fm_data.AM_VIB_EG_carrier SHR 5 AND 1,0) SHL 5;
                           27: fm_data.FEEDBACK_FM :=
                               fm_data.FEEDBACK_FM AND $0fe+
                               _dec(fm_data.FEEDBACK_FM AND 1,0);
                           28: fm_data.FEEDBACK_FM :=
                               fm_data.FEEDBACK_FM AND 1+
                               _dec(fm_data.FEEDBACK_FM SHR 1,0) SHL 1;

                           29,30,31,
                           32: freq_slide :=
                               _dec(freq_slide,-1023);
                           33: Case panning of
                                 0: panning := 1;
                                 2: panning := 0;
                               end;
                           34,
                           35: duration :=
                               _dec(duration,0);
                          end;

               kBkSPC: If NOT shift_pressed then
                         With songdata.instr_macros[instr].data[fmreg_page] do
                           begin
                             Case fmreg_hpos of
                               1: fm_data.ATTCK_DEC_modulator :=
                                  fm_data.ATTCK_DEC_modulator AND $0f;
                               2: fm_data.ATTCK_DEC_modulator :=
                                  fm_data.ATTCK_DEC_modulator AND $0f0;
                               3: fm_data.SUSTN_REL_modulator :=
                                  fm_data.SUSTN_REL_modulator AND $0f;
                               4: fm_data.SUSTN_REL_modulator :=
                                  fm_data.SUSTN_REL_modulator AND $0f0;
                               5: fm_data.WAVEFORM_modulator := 0;
                               6,
                               7: fm_data.KSL_VOLUM_modulator :=
                                  fm_data.KSL_VOLUM_modulator AND $0c0;
                               8: fm_data.KSL_VOLUM_modulator :=
                                  fm_data.KSL_VOLUM_modulator AND $3f;
                               9: fm_data.AM_VIB_EG_modulator :=
                                  fm_data.AM_VIB_EG_modulator AND $0f0;
                              10: fm_data.AM_VIB_EG_modulator :=
                                  fm_data.AM_VIB_EG_modulator AND $7f;
                              11: fm_data.AM_VIB_EG_modulator :=
                                  fm_data.AM_VIB_EG_modulator AND $0bf;
                              12: fm_data.AM_VIB_EG_modulator :=
                                  fm_data.AM_VIB_EG_modulator AND $0ef;
                              13: fm_data.AM_VIB_EG_modulator :=
                                  fm_data.AM_VIB_EG_modulator AND $0df;

                              14: fm_data.ATTCK_DEC_carrier :=
                                  fm_data.ATTCK_DEC_carrier AND $0f;
                              15: fm_data.ATTCK_DEC_carrier :=
                                  fm_data.ATTCK_DEC_carrier AND $0f0;
                              16: fm_data.SUSTN_REL_carrier :=
                                  fm_data.SUSTN_REL_carrier AND $0f;
                              17: fm_data.SUSTN_REL_carrier :=
                                  fm_data.SUSTN_REL_carrier AND $0f0;
                              18: fm_data.WAVEFORM_carrier := 0;
                              19,
                              20: fm_data.KSL_VOLUM_carrier :=
                                  fm_data.KSL_VOLUM_carrier AND $0c0;
                              21: fm_data.KSL_VOLUM_carrier :=
                                  fm_data.KSL_VOLUM_carrier AND $3f;
                              22: fm_data.AM_VIB_EG_carrier :=
                                  fm_data.AM_VIB_EG_carrier AND $0f0;
                              23: fm_data.AM_VIB_EG_carrier :=
                                  fm_data.AM_VIB_EG_carrier AND $7f;
                              24: fm_data.AM_VIB_EG_carrier :=
                                  fm_data.AM_VIB_EG_carrier AND $0bf;
                              25: fm_data.AM_VIB_EG_carrier :=
                                  fm_data.AM_VIB_EG_carrier AND $0ef;
                              26: fm_data.AM_VIB_EG_carrier :=
                                  fm_data.AM_VIB_EG_carrier AND $0df;

                              27: fm_data.FEEDBACK_FM :=
                                  fm_data.FEEDBACK_FM AND $0fe;
                              28: fm_data.FEEDBACK_FM :=
                                  fm_data.FEEDBACK_FM AND $0c1;

                              29,30,31,
                              32: freq_slide := 0;

                              33: panning := 0;
                              34,
                              35: duration := 0;
                             end;

                             If (fmreg_page < 255) then Inc(fmreg_page)
                             else If cycle_pattern then fmreg_page := 1;
                           end
                       else begin
                              FillChar(songdata.instr_macros[instr].data[fmreg_page].fm_data,
                                       SizeOf(songdata.instr_macros[instr].data[fmreg_page].fm_data),0);
                              songdata.instr_macros[instr].data[fmreg_page].freq_slide := 0;
                              songdata.instr_macros[instr].data[fmreg_page].panning := 0;
                              songdata.instr_macros[instr].data[fmreg_page].duration := 0;
                              If (fmreg_page < 255) then Inc(fmreg_page)
                              else If cycle_pattern then fmreg_page := 1;
                            end;

               kCtBkSp: Case fmreg_hpos of
                          1,2,3,4,
                          5: songdata.dis_fmreg_col[instr][fmreg_hpos-1] :=
                               NOT songdata.dis_fmreg_col[instr][fmreg_hpos-1];
                          6,
                          7: songdata.dis_fmreg_col[instr][5] :=
                               NOT songdata.dis_fmreg_col[instr][5];

                          8,9,10,11,12,13,
                          14,15,16,17,
                          18: songdata.dis_fmreg_col[instr][fmreg_hpos-2] :=
                                NOT songdata.dis_fmreg_col[instr][fmreg_hpos-2];
                          19,
                          20: songdata.dis_fmreg_col[instr][17] :=
                                NOT songdata.dis_fmreg_col[instr][17];

                          21,22,23,24,
                          25,26,27,
                          28: songdata.dis_fmreg_col[instr][fmreg_hpos-3] :=
                                NOT songdata.dis_fmreg_col[instr][fmreg_hpos-3];

                          29,30,31,
                          32: songdata.dis_fmreg_col[instr][26] :=
                                NOT songdata.dis_fmreg_col[instr][26];

                          33: songdata.dis_fmreg_col[instr][27] :=
                                NOT songdata.dis_fmreg_col[instr][27];
                        end;

               kAltS:   Case fmreg_hpos of
                          1,2,3,4,
                          5: For temp := 0 to 27 do
                               If (temp <> fmreg_hpos-1) then
                                 songdata.dis_fmreg_col[instr][temp] := TRUE
                               else songdata.dis_fmreg_col[instr][temp] := FALSE;
                          6,
                          7: For temp := 0 to 27 do
                               If (temp <> 5) then
                                 songdata.dis_fmreg_col[instr][temp] := TRUE
                               else songdata.dis_fmreg_col[instr][temp] := FALSE;

                          8,9,10,11,12,13,
                          14,15,16,17,
                          18: For temp := 0 to 27 do
                               If (temp <> fmreg_hpos-2) then
                                 songdata.dis_fmreg_col[instr][temp] := TRUE
                               else songdata.dis_fmreg_col[instr][temp] := FALSE;
                          19,
                          20: For temp := 0 to 27 do
                               If (temp <> 17) then
                                 songdata.dis_fmreg_col[instr][temp] := TRUE
                               else songdata.dis_fmreg_col[instr][temp] := FALSE;

                          21,22,23,24,
                          25,26,27,
                          28: For temp := 0 to 27 do
                               If (temp <> fmreg_hpos-3) then
                                 songdata.dis_fmreg_col[instr][temp] := TRUE
                               else songdata.dis_fmreg_col[instr][temp] := FALSE;

                          29,30,31,
                          32: For temp := 0 to 27 do
                               If (temp <> 26) then
                                 songdata.dis_fmreg_col[instr][temp] := TRUE
                               else songdata.dis_fmreg_col[instr][temp] := FALSE;

                          33: For temp := 0 to 27 do
                               If (temp <> 27) then
                                 songdata.dis_fmreg_col[instr][temp] := TRUE
                               else songdata.dis_fmreg_col[instr][temp] := FALSE;
                        end;

               kAltR: For temp := 0 to 27 do
                        songdata.dis_fmreg_col[instr][temp] := FALSE;

               kAstrsk,
               kNPastr: For temp := 0 to 27 do
                          songdata.dis_fmreg_col[instr][temp] :=
                            NOT songdata.dis_fmreg_col[instr][temp];
             end;

             If (UpCase(CHAR(LO(is_environment.keystroke))) in ['0'..'9','A'..'F']) and
                NOT shift_pressed then
               With songdata.instr_macros[instr].data[fmreg_page] do
                 begin
                   nope := TRUE;
                   Case fmreg_hpos of
                     1: fm_data.ATTCK_DEC_modulator :=
                        hex(CHAR(LO(is_environment.keystroke))) SHL 4+
                        fm_data.ATTCK_DEC_modulator AND $0f;
                     2: fm_data.ATTCK_DEC_modulator :=
                        fm_data.ATTCK_DEC_modulator AND $0f0+
                        hex(CHAR(LO(is_environment.keystroke)));
                     3: fm_data.SUSTN_REL_modulator :=
                        hex(CHAR(LO(is_environment.keystroke))) SHL 4+
                        fm_data.SUSTN_REL_modulator AND $0f;
                     4: fm_data.SUSTN_REL_modulator :=
                        fm_data.SUSTN_REL_modulator AND $0f0+
                        hex(CHAR(LO(is_environment.keystroke)));

                     5: If (hex(CHAR(LO(is_environment.keystroke))) <= 7) then
                          fm_data.WAVEFORM_modulator :=
                          hex(CHAR(LO(is_environment.keystroke)))
                        else nope := FALSE;

                     6: If (hex(CHAR(LO(is_environment.keystroke))) <= 3) then
                          fm_data.KSL_VOLUM_modulator :=
                          fm_data.KSL_VOLUM_modulator AND $0cf+
                          hex(CHAR(LO(is_environment.keystroke))) SHL 4
                        else nope := FALSE;

                     7: fm_data.KSL_VOLUM_modulator :=
                        fm_data.KSL_VOLUM_modulator AND $0f0+
                        hex(CHAR(LO(is_environment.keystroke)));

                     8: If (hex(CHAR(LO(is_environment.keystroke))) <= 3) then
                          fm_data.KSL_VOLUM_modulator :=
                          fm_data.KSL_VOLUM_modulator AND $3f+
                          hex(CHAR(LO(is_environment.keystroke))) SHL 6
                        else nope := FALSE;

                     9: fm_data.AM_VIB_EG_modulator :=
                        fm_data.AM_VIB_EG_modulator AND $0f0+
                        hex(CHAR(LO(is_environment.keystroke)));


                    14: fm_data.ATTCK_DEC_carrier :=
                        hex(CHAR(LO(is_environment.keystroke))) SHL 4+
                        fm_data.ATTCK_DEC_carrier AND $0f;
                    15: fm_data.ATTCK_DEC_carrier :=
                        fm_data.ATTCK_DEC_carrier AND $0f0+
                        hex(CHAR(LO(is_environment.keystroke)));
                    16: fm_data.SUSTN_REL_carrier :=
                        hex(CHAR(LO(is_environment.keystroke))) SHL 4+
                        fm_data.SUSTN_REL_carrier AND $0f;
                    17: fm_data.SUSTN_REL_carrier :=
                        fm_data.SUSTN_REL_carrier AND $0f0+
                        hex(CHAR(LO(is_environment.keystroke)));

                    18: If (hex(CHAR(LO(is_environment.keystroke))) <= 7) then
                          fm_data.WAVEFORM_carrier :=
                          hex(CHAR(LO(is_environment.keystroke)))
                        else nope := FALSE;

                    19: If (hex(CHAR(LO(is_environment.keystroke))) <= 3) then
                          fm_data.KSL_VOLUM_carrier :=
                          fm_data.KSL_VOLUM_carrier AND $0cf+
                          hex(CHAR(LO(is_environment.keystroke))) SHL 4
                        else nope := FALSE;

                    20: fm_data.KSL_VOLUM_carrier :=
                        fm_data.KSL_VOLUM_carrier AND $0f0+
                        hex(CHAR(LO(is_environment.keystroke)));

                    21: If (hex(CHAR(LO(is_environment.keystroke))) <= 3) then
                          fm_data.KSL_VOLUM_carrier :=
                          fm_data.KSL_VOLUM_carrier AND $3f+
                          hex(CHAR(LO(is_environment.keystroke))) SHL 6
                        else nope := FALSE;

                    22: fm_data.AM_VIB_EG_carrier :=
                        fm_data.AM_VIB_EG_carrier AND $0f0+
                        hex(CHAR(LO(is_environment.keystroke)));

                    27: If (hex(CHAR(LO(is_environment.keystroke))) <= 1) then
                          fm_data.FEEDBACK_FM :=
                          hex(CHAR(LO(is_environment.keystroke)))+
                          fm_data.FEEDBACK_FM AND $0fe
                        else nope := FALSE;

                    28: If (hex(CHAR(LO(is_environment.keystroke))) <= 7) then
                          fm_data.FEEDBACK_FM :=
                          fm_data.FEEDBACK_FM AND $0c1+
                          hex(CHAR(LO(is_environment.keystroke))) SHL 1
                        else nope := FALSE;

                    30: If (freq_slide > 0) or
                           ((freq_slide = 0) and
                            (songdata.instr_macros[instr].data[min(fmreg_page-1,1)].freq_slide >= 0)) then
                          freq_slide := freq_slide AND $0ff+
                          hex(CHAR(LO(is_environment.keystroke))) SHL 8
                        else freq_slide := -(Abs(freq_slide) AND $0ff+
                             hex(CHAR(LO(is_environment.keystroke))) SHL 8);

                    31: If (freq_slide > 0) or
                           ((freq_slide = 0) and
                            (songdata.instr_macros[instr].data[min(fmreg_page-1,1)].freq_slide >= 0)) then
                          freq_slide := freq_slide AND $0f0f+
                          hex(CHAR(LO(is_environment.keystroke))) SHL 4
                        else freq_slide := -(Abs(freq_slide) AND $0f0f+
                             hex(CHAR(LO(is_environment.keystroke))) SHL 4);

                    32: If (freq_slide > 0) or
                           ((freq_slide = 0) and
                            (songdata.instr_macros[instr].data[min(fmreg_page-1,1)].freq_slide >= 0)) then
                          freq_slide := freq_slide AND $0ff0+
                          hex(CHAR(LO(is_environment.keystroke)))
                        else freq_slide := -(Abs(freq_slide) AND $0ff0+
                             hex(CHAR(LO(is_environment.keystroke))));

                    34: duration :=
                        duration AND $0f+
                        hex(CHAR(LO(is_environment.keystroke))) SHL 4;
                    35: duration :=
                        duration AND $0f0+
                        hex(CHAR(LO(is_environment.keystroke)));
                    else
                      nope := FALSE;
                   end;

                   If nope then
                     Case fmreg_hpos of
                       6,19,30,31,
                       34:    If NOT (command_typing = 2) then
                                begin
                                  If (fmreg_page < 255) then Inc(fmreg_page)
                                  else If cycle_pattern then fmreg_page := 1;
                                end
                              else begin
                                     Inc(fmreg_hpos);
                                     _scroll_cur_right;
                                   end;
                       7,20,32,
                       35:    begin
                                If (command_typing = 2) then
                                  begin
                                    If (fmreg_hpos <> 32) then Dec(fmreg_hpos)
                                    else Dec(fmreg_hpos,2);
                                    _scroll_cur_left;
                                  end;
                                If (fmreg_page < 255) then Inc(fmreg_page)
                                else If cycle_pattern then fmreg_page := 1;
                              end;
                       else If (fmreg_page < 255) then Inc(fmreg_page)
                            else If cycle_pattern then fmreg_page := 1;
                     end;
                 end;

             If (UpCase(CHAR(LO(is_environment.keystroke))) in ['L','C','R']) and
                NOT shift_pressed then
               With songdata.instr_macros[instr].data[fmreg_page] do
                 begin
                   nope := TRUE;
                   Case fmreg_hpos of
                     33: Case UpCase(CHAR(LO(is_environment.keystroke))) of
                           'L': panning := 1;
                           'C': panning := 0;
                           'R': panning := 2;
                         end;
                     else
                       nope := FALSE;
                   end;

                   If nope then
                     If (fmreg_page < 255) then Inc(fmreg_page)
                     else If cycle_pattern then fmreg_page := 1;
                 end;

             If (UpCase(CHAR(LO(is_environment.keystroke))) in ['+','-']) and
                (fmreg_hpos = 29) then
               With songdata.instr_macros[instr].data[fmreg_page] do
                 begin
                   Case UpCase(CHAR(LO(is_environment.keystroke))) of
                     '+': freq_slide := Abs(freq_slide);
                     '-': freq_slide := -Abs(freq_slide);
                   end;

                   If (fmreg_page < 255) then Inc(fmreg_page)
                   else If cycle_pattern then fmreg_page := 1;
                 end;

             If shift_pressed and ((is_environment.keystroke = kUP) or (is_environment.keystroke = kDOWN)) then
               begin
                 If (ptr_arpeggio_table <> 0) then
                   arpeggio_page := fmreg_page;
                 If (ptr_vibrato_table <> 0) then
                   vibrato_page := fmreg_page;
               end;
           end;

    (* Arpeggio table - pos: 8..13 *)

        8: begin
             is_setting.character_set := ['0'..'9','a'..'f','A'..'F'];
             Repeat
               temps := InputStr(byte2hex(songdata.macro_table[ptr_arpeggio_table].
                                          arpeggio.length),
                                 xstart+60+window_area_inc_x,ystart+4,
                                 2,2,
                                 macro_input_bckg+macro_input,
                                 macro_def_bckg+macro_def);
             until (is_environment.keystroke = kESC) or
                   ((Str2num(temps,16) >= 0) and (Str2num(temps,16) <= 255));

             songdata.macro_table[ptr_arpeggio_table].
             arpeggio.length := Str2num(temps,16);
             Case is_environment.keystroke of
               kCHplus,
               kNPplus: If (songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.length < 255) then
                          Inc(songdata.macro_table[ptr_arpeggio_table].
                              arpeggio.length);
               kCHmins,
               kNPmins: If (songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.length > 0) then
                          Dec(songdata.macro_table[ptr_arpeggio_table].
                              arpeggio.length);
             end;

             If (is_environment.keystroke = kENTER) or
                (is_environment.keystroke = kTAB) or
                (is_environment.keystroke = kDOWN) then pos := 9
             else If (is_environment.keystroke = kUP) then pos := 13
                  else If (is_environment.keystroke = kShTAB) then
                         If NOT arp_vib_mode then pos := 7
                         else pos := 20;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_arp_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If NOT arp_vib_mode then pos := 1
                        else pos := 14;

               kCtRGHT: If arp_vib_mode then pos := 14
                        else If (ptr_vibrato_table <> 0) then pos := 14
                             else pos := 1;

               kCtrlC:  begin
                          clipboard.object_type := objMacroTable;
                          clipboard.mcrtab_type := mttArpeggio_table;
                          copy_object;
                        end;
               kCtrlV,
               kAltP:   paste_object;
             end;
           end;

        9: begin
             is_setting.character_set := ['0'..'9','a'..'f','A'..'F'];
             Repeat
               temps := InputStr(byte2hex(songdata.macro_table[ptr_arpeggio_table].
                                          arpeggio.speed),
                                 xstart+60+window_area_inc_x,ystart+5,
                                 2,2,
                                 macro_input_bckg+macro_input,
                                 macro_def_bckg+macro_def);
             until (is_environment.keystroke = kESC) or
                   ((Str2num(temps,16) >= 0) and (Str2num(temps,16) <= 255));

             songdata.macro_table[ptr_arpeggio_table].
             arpeggio.speed := Str2num(temps,16);
             Case is_environment.keystroke of
               kCHplus,
               kNPplus: If (songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.speed < 255) then
                          Inc(songdata.macro_table[ptr_arpeggio_table].
                              arpeggio.speed);
               kCHmins,
               kNPmins: If (songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.speed > 0) then
                          Dec(songdata.macro_table[ptr_arpeggio_table].
                              arpeggio.speed);
             end;

             If (is_environment.keystroke = kENTER) or
                (is_environment.keystroke = kTAB) or
                (is_environment.keystroke = kDOWN) then pos := 10
             else If (is_environment.keystroke = kUP) or
                     (is_environment.keystroke = kShTAB) then pos := 8;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_arp_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If NOT arp_vib_mode then pos := 1
                        else pos := 15;

               kCtRGHT: If arp_vib_mode then pos := 15
                        else If (ptr_vibrato_table <> 0) then pos := 15
                             else pos := 1;

               kCtrlC:  begin
                          clipboard.object_type := objMacroTable;
                          clipboard.mcrtab_type := mttArpeggio_table;
                          copy_object;
                        end;
               kCtrlV,
               kAltP:   paste_object;
             end;
           end;

       10: begin
             is_setting.character_set := ['0'..'9','a'..'f','A'..'F'];
             Repeat
               temps := InputStr(byte2hex(songdata.macro_table[ptr_arpeggio_table].
                                          arpeggio.loop_begin),
                                 xstart+60+window_area_inc_x,ystart+6,
                                 2,2,
                                 macro_input_bckg+macro_input,
                                 macro_def_bckg+macro_def);
             until (is_environment.keystroke = kESC) or
                   ((Str2num(temps,16) >= 0) and (Str2num(temps,16) <= 255));

             songdata.macro_table[ptr_arpeggio_table].
             arpeggio.loop_begin := Str2num(temps,16);
             Case is_environment.keystroke of
               kCHplus,
               kNPplus: If (songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.loop_begin < 255) then
                          Inc(songdata.macro_table[ptr_arpeggio_table].
                              arpeggio.loop_begin);
               kCHmins,
               kNPmins: If (songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.loop_begin > 0) then
                          Dec(songdata.macro_table[ptr_arpeggio_table].
                              arpeggio.loop_begin);
             end;

             While NOT ((songdata.macro_table[ptr_arpeggio_table].
                         arpeggio.keyoff_pos > songdata.macro_table[ptr_arpeggio_table].
                                               arpeggio.loop_begin+
                                     min0(songdata.macro_table[ptr_arpeggio_table].
                                          arpeggio.loop_length-1,0)) or
                        (songdata.macro_table[ptr_arpeggio_table].
                         arpeggio.loop_begin = 0) or
                        (songdata.macro_table[ptr_arpeggio_table].
                         arpeggio.loop_length = 0) or
                        (songdata.macro_table[ptr_arpeggio_table].
                         arpeggio.keyoff_pos = 0)) do
               Inc(songdata.macro_table[ptr_arpeggio_table].
                   arpeggio.keyoff_pos);

             If (is_environment.keystroke = kENTER) or
                (is_environment.keystroke = kTAB) or
                (is_environment.keystroke = kDOWN) then pos := 11
             else If (is_environment.keystroke = kUP) or
                     (is_environment.keystroke = kShTAB) then pos := 9;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_arp_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If NOT arp_vib_mode then pos := 2
                        else pos := 17;

               kCtRGHT: If arp_vib_mode then pos := 17
                        else If (ptr_vibrato_table <> 0) then pos := 17
                             else pos := 2;

               kCtrlC:  begin
                          clipboard.object_type := objMacroTable;
                          clipboard.mcrtab_type := mttArpeggio_table;
                          copy_object;
                        end;
               kCtrlV,
               kAltP:   paste_object;
             end;
           end;

       11: begin
             is_setting.character_set := ['0'..'9','a'..'f','A'..'F'];
             Repeat
               temps := InputStr(byte2hex(songdata.macro_table[ptr_arpeggio_table].
                                          arpeggio.loop_length),
                                 xstart+60+window_area_inc_x,ystart+7,
                                 2,2,
                                 macro_input_bckg+macro_input,
                                 macro_def_bckg+macro_def);
             until (is_environment.keystroke = kESC) or
                   ((Str2num(temps,16) >= 0) and (Str2num(temps,16) <= 255));

             songdata.macro_table[ptr_arpeggio_table].
             arpeggio.loop_length := Str2num(temps,16);
             Case is_environment.keystroke of
               kCHplus,
               kNPplus: If (songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.loop_length < 255) then
                          Inc(songdata.macro_table[ptr_arpeggio_table].
                              arpeggio.loop_length);
               kCHmins,
               kNPmins: If (songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.loop_length > 0) then
                          Dec(songdata.macro_table[ptr_arpeggio_table].
                              arpeggio.loop_length);
             end;

             While NOT ((songdata.macro_table[ptr_arpeggio_table].
                         arpeggio.keyoff_pos > songdata.macro_table[ptr_arpeggio_table].
                                               arpeggio.loop_begin+
                                     min0(songdata.macro_table[ptr_arpeggio_table].
                                          arpeggio.loop_length-1,0)) or
                        (songdata.macro_table[ptr_arpeggio_table].
                         arpeggio.loop_begin = 0) or
                        (songdata.macro_table[ptr_arpeggio_table].
                         arpeggio.loop_length = 0) or
                        (songdata.macro_table[ptr_arpeggio_table].
                         arpeggio.keyoff_pos = 0)) do
               Inc(songdata.macro_table[ptr_arpeggio_table].
                   arpeggio.keyoff_pos);

             If (is_environment.keystroke = kENTER) or
                (is_environment.keystroke = kTAB) or
                (is_environment.keystroke = kDOWN) then pos := 12
             else If (is_environment.keystroke = kUP) or
                     (is_environment.keystroke = kShTAB) then pos := 10;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_arp_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If NOT arp_vib_mode then pos := 3
                        else pos := 18;

               kCtRGHT: If arp_vib_mode then pos := 18
                        else If (ptr_vibrato_table <> 0) then pos := 18
                             else pos := 3;

               kCtrlC:  begin
                          clipboard.object_type := objMacroTable;
                          clipboard.mcrtab_type := mttArpeggio_table;
                          copy_object;
                        end;
               kCtrlV,
               kAltP:   paste_object;
             end;
           end;

       12: begin
             is_setting.character_set := ['0'..'9','a'..'f','A'..'F'];
             Repeat
               temps := InputStr(byte2hex(songdata.macro_table[ptr_arpeggio_table].
                                           arpeggio.keyoff_pos),
                                 xstart+60+window_area_inc_x,ystart+8,
                                 2,2,
                                 macro_input_bckg+macro_input,
                                 macro_def_bckg+macro_def);
             until (is_environment.keystroke = kESC) or
                   (Str2num(temps,16) >= 0) and (Str2num(temps,16) <= 255) and
                   (Str2num(temps,16) > songdata.macro_table[ptr_arpeggio_table].
                                        arpeggio.loop_begin+
                                        min0(songdata.macro_table[ptr_arpeggio_table].
                                             arpeggio.loop_length-1,0)) or
                   (songdata.macro_table[ptr_arpeggio_table].
                    arpeggio.loop_begin = 0) or
                   (songdata.macro_table[ptr_arpeggio_table].
                    arpeggio.loop_length = 0) or
                   (Str2num(temps,16) = 0);

             songdata.macro_table[ptr_arpeggio_table].
             arpeggio.keyoff_pos := Str2num(temps,16);
             Case is_environment.keystroke of
               kCHplus,
               kNPplus: If (songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.loop_begin = 0) or
                           (songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.loop_length = 0) or
                           (songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.keyoff_pos <> 0) then
                          If (songdata.macro_table[ptr_arpeggio_table].
                              arpeggio.keyoff_pos < 255) then
                            Inc(songdata.macro_table[ptr_arpeggio_table].
                                arpeggio.keyoff_pos)
                          else
                        else If (songdata.macro_table[ptr_arpeggio_table].
                                 arpeggio.loop_begin+
                                 songdata.macro_table[ptr_arpeggio_table].
                                 arpeggio.loop_length <= 255) then
                               songdata.macro_table[ptr_arpeggio_table].
                               arpeggio.keyoff_pos :=
                                 songdata.macro_table[ptr_arpeggio_table].
                                 arpeggio.loop_begin+
                                 songdata.macro_table[ptr_arpeggio_table].
                                 arpeggio.loop_length;
               kCHmins,
               kNPmins: If (min0(songdata.macro_table[ptr_arpeggio_table].
                                 arpeggio.keyoff_pos-1,0) > songdata.macro_table[ptr_arpeggio_table].
                                                            arpeggio.loop_begin+
                              min0(songdata.macro_table[ptr_arpeggio_table].
                                   arpeggio.loop_length-1,0)) or
                           ((songdata.macro_table[ptr_arpeggio_table].
                             arpeggio.keyoff_pos > 0) and
                           ((songdata.macro_table[ptr_arpeggio_table].
                             arpeggio.loop_begin = 0) or
                            (songdata.macro_table[ptr_arpeggio_table].
                             arpeggio.loop_length = 0))) then
                          Dec(songdata.macro_table[ptr_arpeggio_table].
                              arpeggio.keyoff_pos);
             end;

             If (is_environment.keystroke = kENTER) or
                (is_environment.keystroke = kTAB) or
                (is_environment.keystroke = kDOWN) then pos := 13
             else If (is_environment.keystroke = kUP) or
                     (is_environment.keystroke = kShTAB) then pos := 11;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_arp_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If NOT arp_vib_mode then pos := 4
                        else pos := 19;

               kCtRGHT: If arp_vib_mode then pos := 19
                        else If (ptr_vibrato_table <> 0) then pos := 19
                             else pos := 4;

               kCtrlC:  begin
                          clipboard.object_type := objMacroTable;
                          clipboard.mcrtab_type := mttArpeggio_table;
                          copy_object;
                        end;
               kCtrlV,
               kAltP:   paste_object;
             end;
           end;

       13: begin
             GotoXY(xstart+55+window_area_inc_x,ystart+16+(window_area_inc_y DIV 2));
             is_environment.keystroke := getkey;
             If _check_macro_speed_change then GOTO _jmp2;
             _check_arp_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If NOT shift_pressed then
                          If NOT arp_vib_mode then pos := 7
                          else pos := 20
                        else If (arpeggio_page > songdata.macro_table[ptr_arpeggio_table].arpeggio.length) then
                               arpeggio_page := min(1,songdata.macro_table[ptr_arpeggio_table].arpeggio.length)
                             else arpeggio_page := 1;

               kCtRGHT: If NOT shift_pressed then
                          If NOT arp_vib_mode then
                            If (ptr_vibrato_table <> 0) then pos := 20
                            else pos := 7
                          else pos := 20
                        else If (arpeggio_page < songdata.macro_table[ptr_arpeggio_table].arpeggio.length) then
                               arpeggio_page := min(1,songdata.macro_table[ptr_arpeggio_table].arpeggio.length)
                             else arpeggio_page := 255;

               kUP: If (arpeggio_page > 1) then Dec(arpeggio_page)
                    else If cycle_pattern then arpeggio_page := 255;

               kDOWN: If (arpeggio_page < 255) then Inc(arpeggio_page)
                      else If cycle_pattern then arpeggio_page := 1;

               kPgUP: If (arpeggio_page > 16) then Dec(arpeggio_page,16)
                      else arpeggio_page := 1;

               kPgDOWN: If (arpeggio_page+16 < 255) then Inc(arpeggio_page,16)
                        else arpeggio_page := 255;

               kHOME: arpeggio_page := 1;

               kEND: arpeggio_page := 255;

               kENTER,kTAB: If NOT arp_vib_mode then
                              If (ptr_vibrato_table <> 0) then pos := 14
                              else pos := 1
                            else pos := 14;

               kShTAB: pos := 12;

               kCtrlC: begin
                         If NOT shift_pressed then clipboard.object_type := objMacroTableLine
                         else clipboard.object_type := objMacroTableColumn;
                         clipboard.mcrtab_type := mttArpeggio_table;
                         copy_object;
                       end;
               kCtrlV,
               kAltP: begin
                        paste_object;
                        If (clipboard.object_type = objMacroTableLine) and
                           (clipboard.mcrtab_type = mttArpeggio_table) then
                          If (arpeggio_page < 255) then Inc(arpeggio_page)
                          else If cycle_pattern then arpeggio_page := 1;
                      end;

               kCHplus,
               kNPplus: If (songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.data[arpeggio_page] < $80) then
                          If (songdata.macro_table[ptr_arpeggio_table].
                              arpeggio.data[arpeggio_page] < 96) then
                            Inc(songdata.macro_table[ptr_arpeggio_table].
                                arpeggio.data[arpeggio_page])
                          else
                        else If (songdata.macro_table[ptr_arpeggio_table].
                                 arpeggio.data[arpeggio_page] < $80+96+1) then
                               Inc(songdata.macro_table[ptr_arpeggio_table].
                                   arpeggio.data[arpeggio_page]);
               kCHmins,
               kNPmins: If (songdata.macro_table[ptr_arpeggio_table].
                            arpeggio.data[arpeggio_page] < $80) then
                          If (songdata.macro_table[ptr_arpeggio_table].
                              arpeggio.data[arpeggio_page] > 1) then
                            Dec(songdata.macro_table[ptr_arpeggio_table].
                                arpeggio.data[arpeggio_page])
                          else
                        else If (songdata.macro_table[ptr_arpeggio_table].
                                 arpeggio.data[arpeggio_page] > $80+1) then
                               Dec(songdata.macro_table[ptr_arpeggio_table].
                                   arpeggio.data[arpeggio_page]);

               kBkSPC: begin
                         songdata.macro_table[ptr_arpeggio_table].
                         arpeggio.data[arpeggio_page] := 0;
                         If (arpeggio_page < 255) then Inc(arpeggio_page)
                         else If cycle_pattern then arpeggio_page := 1;
                       end;

               kINSERT: begin
                          For temp := 255-1 downto arpeggio_page do
                            begin
                              songdata.macro_table[ptr_arpeggio_table].
                              arpeggio.data[SUCC(temp)] :=
                                songdata.macro_table[ptr_arpeggio_table].
                                arpeggio.data[temp]
                            end;
                          FillChar(songdata.macro_table[ptr_arpeggio_table].
                                   arpeggio.data[arpeggio_page],
                                   SizeOf(songdata.macro_table[ptr_arpeggio_table].
                                          arpeggio.data[arpeggio_page]),0);
                        end;

               kDELETE: begin
                          For temp := arpeggio_page to 255-1 do
                            begin
                              songdata.macro_table[ptr_arpeggio_table].
                              arpeggio.data[temp] :=
                                songdata.macro_table[ptr_arpeggio_table].
                                arpeggio.data[SUCC(temp)]
                            end;
                          FillChar(songdata.macro_table[ptr_arpeggio_table].
                                   arpeggio.data[255],
                                   SizeOf(songdata.macro_table[ptr_arpeggio_table].
                                          arpeggio.data[255]),0);
                        end;
             end;

             If shift_pressed and ((is_environment.keystroke = kUP) or (is_environment.keystroke = kDOWN)) then
               begin
                 fmreg_page := arpeggio_page;
                 If (ptr_vibrato_table <> 0) then
                   vibrato_page := arpeggio_page;
               end;

             If (UpCase(CHAR(LO(is_environment.keystroke))) in ['A',UpCase(b_note),'C'..'G']) and
                NOT shift_pressed then
               begin
                 nope := FALSE;
                 is_setting.append_enabled := FALSE;
                 is_setting.character_set  := ['1'..'9','a',b_note,'c'..'g',
                                               'A',UpCase(b_note),'C'..'F','#','-'];
                 is_environment.locate_pos := 2;
                 tstr := CHAR(LO(is_environment.keystroke));

                 Repeat
                   tstr := InputStr(tstr,xstart+55+window_area_inc_x,ystart+16+(window_area_inc_y DIV 2),3,3,
                                    macro_input_bckg+macro_input,
                                    macro_def_bckg+macro_def);
                   is_setting.append_enabled := TRUE;

                   If (UpCase(tstr[1]) in ['+','0'..'9','A',UpCase(b_note),'C'..'G']) and
                     ((is_environment.keystroke = kENTER) or
                      (is_environment.keystroke = kUP) or
                      (is_environment.keystroke = kDOWN) or
                      (is_environment.keystroke = kTAB) or
                      (is_environment.keystroke = kShTAB)) then
                     begin
                       nope := FALSE;
                       If (tstr[1] = '+') then Delete(tstr,1,1);
                       If (tstr[1] in ['0'..'9']) and
                          (Str2num(tstr,10) >= 0) and (Str2num(tstr,10) <= 96) then
                         begin
                           nope := TRUE;
                           songdata.macro_table[ptr_arpeggio_table].
                           arpeggio.data[arpeggio_page] := Str2num(tstr,10);
                           If (arpeggio_page < 255) then Inc(arpeggio_page)
                           else If cycle_pattern then arpeggio_page := 1;
                         end
                       else begin
                              If (Length(tstr) = 2) then
                                If tstr[2] in ['1'..'9'] then Insert('-',tstr,2)
                                else If tstr[2] in ['-','#'] then
                                       tstr := tstr + Num2str(current_octave,10);

                              If (Length(tstr) = 1) then
                                tstr := tstr + '-' + Num2str(current_octave,10);

                              For temp1 := 1 to 12*8+1 do
                                If (Upper(tstr) = note_layout[temp1]) then
                                  begin
                                    nope := TRUE;
                                    songdata.macro_table[ptr_arpeggio_table].
                                    arpeggio.data[arpeggio_page] := $80+temp1;
                                    BREAK;
                                  end;

                              If NOT nope and (Length(tstr) = 2) then
                                For temp1 := 1 to 12*8+1 do
                                  If (Copy(Upper(tstr),1,2) = Copy(note_layout[temp1],1,2)) then
                                    begin
                                      nope := TRUE;
                                      songdata.macro_table[ptr_arpeggio_table].
                                      arpeggio.data[arpeggio_page] := $80+temp1;
                                      BREAK;
                                    end;

                              If nope then
                                Case is_environment.keystroke of
                                  kUP:
                                    If (arpeggio_page > 1) then Dec(arpeggio_page)
                                    else If cycle_pattern then arpeggio_page := 255;

                                  kDOWN,
                                  kENTER:
                                    If (arpeggio_page < 255) then Inc(arpeggio_page)
                                    else If cycle_pattern then arpeggio_page := 1;
                                end;

                              If NOT nope then
                                Case songdata.macro_table[ptr_arpeggio_table].
                                     arpeggio.data[arpeggio_page] of
                                  0: tstr := '+0';
                                  1..96: tstr := '+'+Num2str(songdata.macro_table[ptr_arpeggio_table].
                                                             arpeggio.data[arpeggio_page],10);
                                  $80..$80+12*8+1:
                                     tstr := note_layout[songdata.macro_table[ptr_arpeggio_table].
                                                         arpeggio.data[arpeggio_page]-$80];
                                end;
                            end;
                     end;
                 until (nope or (is_environment.keystroke = kESC)) and
                       ((is_environment.keystroke = kESC) or
                        (is_environment.keystroke = kENTER) or
                        (is_environment.keystroke = kUP) or
                        (is_environment.keystroke = kDOWN) or
                        (is_environment.keystroke = kTAB) or
                        (is_environment.keystroke = kShTAB));
                 nope := FALSE;
                 Case is_environment.keystroke of
                   kTAB: If (ptr_vibrato_table <> 0) then pos := 14
                         else pos := 1;
                   kShTAB: pos := 12;
                   kESC: is_environment.keystroke := kENTER;
                 end;
               end;

             If (UpCase(CHAR(LO(is_environment.keystroke))) in ['+','0'..'9']) and
                NOT shift_pressed then
               begin
                 nope := FALSE;
                 is_setting.append_enabled := FALSE;
                 is_setting.character_set  := ['+','0'..'9'];
                 is_environment.locate_pos := 2;
                 tstr := CHAR(LO(is_environment.keystroke));

                 If (CHAR(LO(is_environment.keystroke)) <> '+') then
                   begin
                     tstr := '+'+tstr;
                     Inc(is_environment.locate_pos);
                   end;

                 Repeat
                   tstr := InputStr(tstr,xstart+55+window_area_inc_x,ystart+16+(window_area_inc_y DIV 2),3,3,
                                    macro_input_bckg+macro_input,
                                    macro_def_bckg+macro_def);
                   is_setting.append_enabled := TRUE;

                   temps := tstr;
                   If ((is_environment.keystroke = kENTER) or
                       (is_environment.keystroke = kUP) or
                       (is_environment.keystroke = kDOWN) or
                       (is_environment.keystroke = kTAB) or
                       (is_environment.keystroke = kShTAB)) then
                     begin
                       nope := FALSE;
                       If (tstr[1] = '+') then Delete(tstr,1,1);

                       If (tstr[1] in ['0'..'9']) and
                          (Str2num(tstr,10) >= 0) and (Str2num(tstr,10) <= 96) then
                         begin
                           nope := TRUE;
                           songdata.macro_table[ptr_arpeggio_table].
                           arpeggio.data[arpeggio_page] := Str2num(tstr,10);
                         end
                       else tstr := temps;

                       If nope then
                         Case is_environment.keystroke of
                           kUP:
                             If (arpeggio_page > 1) then Dec(arpeggio_page)
                             else If cycle_pattern then arpeggio_page := 255;

                           kDOWN,
                           kENTER:
                             If (arpeggio_page < 255) then Inc(arpeggio_page)
                             else If cycle_pattern then arpeggio_page := 1;
                         end;

                       If NOT nope then
                         Case songdata.macro_table[ptr_arpeggio_table].
                              arpeggio.data[arpeggio_page] of
                           0: tstr := '+0';
                           1..96: tstr := '+'+Num2str(songdata.macro_table[ptr_arpeggio_table].
                                                      arpeggio.data[arpeggio_page],10);
                           $80..$80+12*8+1:
                              tstr := note_layout[songdata.macro_table[ptr_arpeggio_table].
                                                  arpeggio.data[arpeggio_page]-$80];
                         end;
                     end;
                 until (nope or (is_environment.keystroke = kESC)) and
                       ((is_environment.keystroke = kESC) or
                        (is_environment.keystroke = kENTER) or
                        (is_environment.keystroke = kUP) or
                        (is_environment.keystroke = kDOWN) or
                        (is_environment.keystroke = kTAB) or
                        (is_environment.keystroke = kShTAB));
                 nope := FALSE;
                 Case is_environment.keystroke of
                   kTAB: If NOT arp_vib_mode then
                           If (ptr_vibrato_table <> 0) then pos := 14
                           else pos := 1
                         else pos := 14;
                   kShTAB: pos := 12;
                   kESC: is_environment.keystroke := kENTER;
                 end;
               end;
           end;

    (* Vibrato table - pos: 14..20 *)

       14: begin
             is_setting.character_set := ['0'..'9','a'..'f','A'..'F'];
             Repeat
               temps := InputStr(byte2hex(songdata.macro_table[ptr_vibrato_table].
                                          vibrato.length),
                                 xstart+77+window_area_inc_x,ystart+4,
                                 2,2,
                                 macro_input_bckg+macro_input,
                                 macro_def_bckg+macro_def);
             until (is_environment.keystroke = kESC) or
                   ((Str2num(temps,16) >= 0) and (Str2num(temps,16) <= 255));

             songdata.macro_table[ptr_vibrato_table].
                      vibrato.length := Str2num(temps,16);
             Case is_environment.keystroke of
               kCHplus,
               kNPplus: If (songdata.macro_table[ptr_vibrato_table].
                            vibrato.length < 255) then
                          Inc(songdata.macro_table[ptr_vibrato_table].
                              vibrato.length);
               kCHmins,
               kNPmins: If (songdata.macro_table[ptr_vibrato_table].
                            vibrato.length > 0) then
                          Dec(songdata.macro_table[ptr_vibrato_table].
                              vibrato.length);
             end;

             If (is_environment.keystroke = kENTER) or
                (is_environment.keystroke = kTAB) or
                (is_environment.keystroke = kDOWN) then pos := 15
             else If (is_environment.keystroke = kUP) then pos := 20
                  else If (is_environment.keystroke = kShTAB) then
                         If NOT arp_vib_mode then
                           If (ptr_arpeggio_table <> 0) then pos := 13
                           else pos := 7
                         else pos := 13;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_vib_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If arp_vib_mode then pos := 8
                        else If (ptr_arpeggio_table <> 0) then pos := 8
                             else pos := 1;

               kCtRGHT: If arp_vib_mode then pos := 8
                        else pos := 1;

               kCtrlC:  begin
                          clipboard.object_type := objMacroTable;
                          clipboard.mcrtab_type := mttVibrato_table;
                          copy_object;
                        end;
               kCtrlV,
               kAltP:   paste_object;
             end;
           end;

       15: begin
             is_setting.character_set := ['0'..'9','a'..'f','A'..'F'];
             Repeat
               temps := InputStr(byte2hex(songdata.macro_table[ptr_vibrato_table].
                                          vibrato.speed),
                                 xstart+77+window_area_inc_x,ystart+5,
                                 2,2,
                                 macro_input_bckg+macro_input,
                                 macro_def_bckg+macro_def);
             until (is_environment.keystroke = kESC) or
                   ((Str2num(temps,16) >= 0) and (Str2num(temps,16) <= 255));

             songdata.macro_table[ptr_vibrato_table].
                      vibrato.speed := Str2num(temps,16);
             Case is_environment.keystroke of
               kCHplus,
               kNPplus: If (songdata.macro_table[ptr_vibrato_table].
                            vibrato.speed < 255) then
                          Inc(songdata.macro_table[ptr_vibrato_table].
                              vibrato.speed);
               kCHmins,
               kNPmins: If (songdata.macro_table[ptr_vibrato_table].
                            vibrato.speed > 0) then
                          Dec(songdata.macro_table[ptr_vibrato_table].
                              vibrato.speed);
             end;

             If (is_environment.keystroke = kENTER) or
                (is_environment.keystroke = kTAB) or
                (is_environment.keystroke = kDOWN) then pos := 16
             else If (is_environment.keystroke = kUP) or
                     (is_environment.keystroke = kShTAB) then pos := 14;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_vib_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If arp_vib_mode then pos := 9
                        else If (ptr_arpeggio_table <> 0) then pos := 9
                             else pos := 1;

               kCtRGHT: If arp_vib_mode then pos := 9
                        else pos := 1;

               kCtrlC:  begin
                          clipboard.object_type := objMacroTable;
                          clipboard.mcrtab_type := mttVibrato_table;
                          copy_object;
                        end;
               kCtrlV,
               kAltP:   paste_object;
             end;
           end;

       16: begin
             is_setting.character_set := ['0'..'9','a'..'f','A'..'F'];
             Repeat
               temps := InputStr(byte2hex(songdata.macro_table[ptr_vibrato_table].
                                          vibrato.delay),
                                 xstart+77+window_area_inc_x,ystart+6,
                                 2,2,
                                 macro_input_bckg+macro_input,
                                 macro_def_bckg+macro_def);
             until (is_environment.keystroke = kESC) or
                   ((Str2num(temps,16) >= 0) and (Str2num(temps,16) <= 255));

             songdata.macro_table[ptr_vibrato_table].
                      vibrato.delay := Str2num(temps,16);
             Case is_environment.keystroke of
               kCHplus,
               kNPplus: If (songdata.macro_table[ptr_vibrato_table].
                            vibrato.delay < 255) then
                          Inc(songdata.macro_table[ptr_vibrato_table].
                              vibrato.delay);
               kCHmins,
               kNPmins: If (songdata.macro_table[ptr_vibrato_table].
                            vibrato.delay > 0) then
                          Dec(songdata.macro_table[ptr_vibrato_table].
                              vibrato.delay);
             end;

             If (is_environment.keystroke = kENTER) or
                (is_environment.keystroke = kTAB) or
                (is_environment.keystroke = kDOWN) then pos := 17
             else If (is_environment.keystroke = kUP) or
                     (is_environment.keystroke = kShTAB) then pos := 15;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_vib_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If arp_vib_mode then pos := 8
                        else If (ptr_arpeggio_table <> 0) then pos := 8
                             else pos := 1;

               kCtRGHT: If arp_vib_mode then pos := 8
                        else pos := 1;

               kCtrlC:  begin
                          clipboard.object_type := objMacroTable;
                          clipboard.mcrtab_type := mttVibrato_table;
                          copy_object;
                        end;
               kCtrlV,
               kAltP:   paste_object;
             end;
           end;

       17: begin
             is_setting.character_set := ['0'..'9','a'..'f','A'..'F'];
             Repeat
               temps := InputStr(byte2hex(songdata.macro_table[ptr_vibrato_table].
                                          vibrato.loop_begin),
                                 xstart+77+window_area_inc_x,ystart+7,
                                 2,2,
                                 macro_input_bckg+macro_input,
                                 macro_def_bckg+macro_def);
             until (is_environment.keystroke = kESC) or
                   ((Str2num(temps,16) >= 0) and (Str2num(temps,16) <= 255));

             songdata.macro_table[ptr_vibrato_table].
                      vibrato.loop_begin := Str2num(temps,16);
             Case is_environment.keystroke of
               kCHplus,
               kNPplus: If (songdata.macro_table[ptr_vibrato_table].
                            vibrato.loop_begin < 255) then
                          Inc(songdata.macro_table[ptr_vibrato_table].
                              vibrato.loop_begin);
               kCHmins,
               kNPmins: If (songdata.macro_table[ptr_vibrato_table].
                            vibrato.loop_begin > 0) then
                          Dec(songdata.macro_table[ptr_vibrato_table].
                              vibrato.loop_begin);
             end;

             While NOT ((songdata.macro_table[ptr_vibrato_table].
                         vibrato.keyoff_pos > songdata.macro_table[ptr_vibrato_table].
                                              vibrato.loop_begin+
                                     min0(songdata.macro_table[ptr_vibrato_table].
                                          vibrato.loop_length-1,0)) or
                        (songdata.macro_table[ptr_vibrato_table].
                         vibrato.loop_begin = 0) or
                        (songdata.macro_table[ptr_vibrato_table].
                         vibrato.loop_length = 0) or
                        (songdata.macro_table[ptr_vibrato_table].
                         vibrato.keyoff_pos = 0)) do
               Inc(songdata.macro_table[ptr_vibrato_table].
                   vibrato.keyoff_pos);

             If (is_environment.keystroke = kENTER) or
                (is_environment.keystroke = kTAB) or
                (is_environment.keystroke = kDOWN) then pos := 18
             else If (is_environment.keystroke = kUP) or
                     (is_environment.keystroke = kShTAB) then pos := 16;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_vib_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If arp_vib_mode then pos := 10
                        else If (ptr_arpeggio_table <> 0) then pos := 10
                             else pos := 2;

               kCtRGHT: If arp_vib_mode then pos := 10
                        else pos := 2;

               kCtrlC:  begin
                          clipboard.object_type := objMacroTable;
                          clipboard.mcrtab_type := mttVibrato_table;
                          copy_object;
                        end;
               kCtrlV,
               kAltP:   paste_object;
             end;
           end;

       18: begin
             is_setting.character_set := ['0'..'9','a'..'f','A'..'F'];
             Repeat
               temps := InputStr(byte2hex(songdata.macro_table[ptr_vibrato_table].
                                          vibrato.loop_length),
                                 xstart+77+window_area_inc_x,ystart+8,
                                 2,2,
                                 macro_input_bckg+macro_input,
                                 macro_def_bckg+macro_def);
             until (is_environment.keystroke = kESC) or
                   ((Str2num(temps,16) >= 0) and (Str2num(temps,16) <= 255));

             songdata.macro_table[ptr_vibrato_table].
                      vibrato.loop_length := Str2num(temps,16);
             Case is_environment.keystroke of
               kCHplus,
               kNPplus: If (songdata.macro_table[ptr_vibrato_table].
                            vibrato.loop_length < 255) then
                          Inc(songdata.macro_table[ptr_vibrato_table].
                              vibrato.loop_length);
               kCHmins,
               kNPmins: If (songdata.macro_table[ptr_vibrato_table].
                            vibrato.loop_length > 0) then
                          Dec(songdata.macro_table[ptr_vibrato_table].
                              vibrato.loop_length);
             end;

             While NOT ((songdata.macro_table[ptr_vibrato_table].
                         vibrato.keyoff_pos > songdata.macro_table[ptr_vibrato_table].
                                              vibrato.loop_begin+
                                     min0(songdata.macro_table[ptr_vibrato_table].
                                          vibrato.loop_length-1,0)) or
                        (songdata.macro_table[ptr_vibrato_table].
                         vibrato.loop_begin = 0) or
                        (songdata.macro_table[ptr_vibrato_table].
                         vibrato.loop_length = 0) or
                        (songdata.macro_table[ptr_vibrato_table].
                         vibrato.keyoff_pos = 0)) do
               Inc(songdata.macro_table[ptr_vibrato_table].
                   vibrato.keyoff_pos);

             If (is_environment.keystroke = kENTER) or
                (is_environment.keystroke = kTAB) or
                (is_environment.keystroke = kDOWN) then pos := 19
             else If (is_environment.keystroke = kUP) or
                     (is_environment.keystroke = kShTAB) then pos := 17;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_vib_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If arp_vib_mode then pos := 11
                        else If (ptr_arpeggio_table <> 0) then pos := 11
                             else pos := 3;

               kCtRGHT: If arp_vib_mode then pos := 11
                        else pos := 3;

               kCtrlC:  begin
                          clipboard.object_type := objMacroTable;
                          clipboard.mcrtab_type := mttVibrato_table;
                          copy_object;
                        end;
               kCtrlV,
               kAltP:   paste_object;
             end;
           end;

       19: begin
             is_setting.character_set := ['0'..'9','a'..'f','A'..'F'];
             Repeat
               temps := InputStr(byte2hex(songdata.macro_table[ptr_vibrato_table].
                                          vibrato.keyoff_pos),
                                 xstart+77+window_area_inc_x,ystart+9,
                                 2,2,
                                 macro_input_bckg+macro_input,
                                 macro_def_bckg+macro_def);
             until (is_environment.keystroke = kESC) or
                   (Str2num(temps,16) >= 0) and (Str2num(temps,16) <= 255) and
                   (Str2num(temps,16) > songdata.macro_table[ptr_vibrato_table].
                                        vibrato.loop_begin+
                                        min0(songdata.macro_table[ptr_vibrato_table].
                                             vibrato.loop_length-1,0)) or
                   (songdata.macro_table[ptr_vibrato_table].
                    vibrato.loop_begin = 0) or
                   (songdata.macro_table[ptr_vibrato_table].
                    vibrato.loop_length = 0) or
                   (Str2num(temps,16) = 0);

             songdata.macro_table[ptr_vibrato_table].
                      vibrato.keyoff_pos := Str2num(temps,16);
             Case is_environment.keystroke of
               kCHplus,
               kNPplus: If (songdata.macro_table[ptr_vibrato_table].
                            vibrato.loop_begin = 0) or
                           (songdata.macro_table[ptr_vibrato_table].
                            vibrato.loop_length = 0) or
                           (songdata.macro_table[ptr_vibrato_table].
                            vibrato.keyoff_pos <> 0) then
                          If (songdata.macro_table[ptr_vibrato_table].
                              vibrato.keyoff_pos < 255) then
                            Inc(songdata.macro_table[ptr_vibrato_table].
                                vibrato.keyoff_pos)
                          else
                        else If (songdata.macro_table[ptr_vibrato_table].
                                 vibrato.loop_begin+
                                 songdata.macro_table[ptr_vibrato_table].
                                 vibrato.loop_length <= 255) then
                               songdata.macro_table[ptr_vibrato_table].
                               vibrato.keyoff_pos :=
                                 songdata.macro_table[ptr_vibrato_table].
                                 vibrato.loop_begin+
                                 songdata.macro_table[ptr_vibrato_table].
                                 vibrato.loop_length;
               kCHmins,
               kNPmins: If (min0(songdata.macro_table[ptr_vibrato_table].
                                 vibrato.keyoff_pos-1,0) > songdata.macro_table[ptr_vibrato_table].
                                                           vibrato.loop_begin+
                              min0(songdata.macro_table[ptr_vibrato_table].
                                   vibrato.loop_length-1,0)) or
                           ((songdata.macro_table[ptr_vibrato_table].
                             vibrato.keyoff_pos > 0) and
                           ((songdata.macro_table[ptr_vibrato_table].
                             vibrato.loop_begin = 0) or
                            (songdata.macro_table[ptr_vibrato_table].
                             vibrato.loop_length = 0))) then
                          Dec(songdata.macro_table[ptr_vibrato_table].
                              vibrato.keyoff_pos);
             end;

             If (is_environment.keystroke = kENTER) or
                (is_environment.keystroke = kTAB) or
                (is_environment.keystroke = kDOWN) then pos := 20
             else If (is_environment.keystroke = kUP) or
                     (is_environment.keystroke = kShTAB) then pos := 18;

             If _check_macro_speed_change then GOTO _jmp2;
             _check_vib_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If arp_vib_mode then pos := 12
                        else If (ptr_arpeggio_table <> 0) then pos := 12
                             else pos := 4;

               kCtRGHT: If arp_vib_mode then pos := 12
                        else pos := 4;

               kCtrlC:  begin
                          clipboard.object_type := objMacroTable;
                          clipboard.mcrtab_type := mttVibrato_table;
                          copy_object;
                        end;
               kCtrlV,
               kAltP:   paste_object;
             end;
           end;

       20: begin
             GotoXY(xstart+72+vibrato_hpos-1+window_area_inc_x,ystart+16+(window_area_inc_y DIV 2));
             is_environment.keystroke := getkey;
             If _check_macro_speed_change then GOTO _jmp2;
             _check_vib_general_keys;

             Case is_environment.keystroke of
               kCtLEFT: If NOT shift_pressed then
                          If NOT arp_vib_mode then
                            If (ptr_arpeggio_table <> 0) then pos := 13
                            else pos := 7
                          else pos := 13
                        else If (vibrato_page > songdata.macro_table[ptr_vibrato_table].vibrato.length) then
                               vibrato_page := min(1,songdata.macro_table[ptr_vibrato_table].vibrato.length)
                             else vibrato_page := 1;

               kCtRGHT: If NOT shift_pressed then
                          If NOT arp_vib_mode then pos := 7
                          else pos := 13
                        else If (vibrato_page < songdata.macro_table[ptr_vibrato_table].vibrato.length) then
                               vibrato_page := min(1,songdata.macro_table[ptr_vibrato_table].vibrato.length)
                             else vibrato_page := 255;

               kUP: If (vibrato_page > 1) then Dec(vibrato_page)
                    else If cycle_pattern then vibrato_page := 255;

               kDOWN: If (vibrato_page < 255) then Inc(vibrato_page)
                      else If cycle_pattern then vibrato_page := 1;

               kPgUP: If (vibrato_page > 16) then Dec(vibrato_page,16)
                      else vibrato_page := 1;

               kPgDOWN: If (vibrato_page+16 < 255) then Inc(vibrato_page,16)
                        else vibrato_page := 255;

               kHOME: vibrato_page := 1;

               kEND: vibrato_page := 255;

               kLEFT: If (vibrato_hpos > 1) then Dec(vibrato_hpos)
                      else vibrato_hpos := 3;

               kRIGHT: If (vibrato_hpos < 3) then Inc(vibrato_hpos)
                       else vibrato_hpos := 1;

               kENTER,kTAB: If NOT arp_vib_mode then pos := 1
                            else pos := 8;

               kShTAB: pos := 19;

               kCtrlC: begin
                         If NOT shift_pressed then clipboard.object_type := objMacroTableLine
                         else clipboard.object_type := objMacroTableColumn;
                         clipboard.mcrtab_type := mttVibrato_table;
                         copy_object;
                       end;
               kCtrlV,
               kAltP: begin
                        paste_object;
                        If (clipboard.object_type = objMacroTableLine) and
                           (clipboard.mcrtab_type = mttVibrato_table) then
                          If (vibrato_page < 255) then Inc(vibrato_page)
                          else If cycle_pattern then vibrato_page := 1;
                      end;

               kBkSPC: begin
                         songdata.macro_table[ptr_vibrato_table].
                         vibrato.data[vibrato_page] := 0;
                         If (vibrato_page < 255) then Inc(vibrato_page)
                         else If cycle_pattern then vibrato_page := 1;
                       end;

               kINSERT: begin
                          For temp := 255-1 downto vibrato_page do
                            begin
                              songdata.macro_table[ptr_vibrato_table].
                              vibrato.data[SUCC(temp)] :=
                                songdata.macro_table[ptr_vibrato_table].
                                vibrato.data[temp]
                            end;
                          FillChar(songdata.macro_table[ptr_vibrato_table].
                                   vibrato.data[vibrato_page],
                                   SizeOf(songdata.macro_table[ptr_vibrato_table].
                                          vibrato.data[vibrato_page]),0);
                        end;

               kDELETE: begin
                          For temp := vibrato_page to 255-1 do
                            begin
                              songdata.macro_table[ptr_vibrato_table].
                              vibrato.data[temp] :=
                                songdata.macro_table[ptr_vibrato_table].
                                vibrato.data[SUCC(temp)]
                            end;
                          FillChar(songdata.macro_table[ptr_vibrato_table].
                                   vibrato.data[255],
                                   SizeOf(songdata.macro_table[ptr_vibrato_table].
                                          vibrato.data[255]),0);
                        end;
             end;

             If shift_pressed and ((is_environment.keystroke = kUP) or (is_environment.keystroke = kDOWN)) then
               begin
                 fmreg_page := vibrato_page;
                 If (ptr_arpeggio_table <> 0) then
                   arpeggio_page := vibrato_page;
               end;

             If (UpCase(CHAR(LO(is_environment.keystroke))) in ['0'..'9','A'..'F','+','-']) then
               With songdata.macro_table[ptr_vibrato_table].vibrato do
                 begin
                   nope := TRUE;
                   Case vibrato_hpos of
                     1: Case UpCase(CHAR(LO(is_environment.keystroke))) of
                          '+': data[vibrato_page] := Abs(data[vibrato_page]);
                          '-': data[vibrato_page] := -Abs(data[vibrato_page]);
                          else nope := FALSE;
                        end;

                     2: Case UpCase(CHAR(LO(is_environment.keystroke))) of
                          '0'..'7': If (data[vibrato_page] > 0) or
                                       ((data[vibrato_page] = 0) and
                                        (data[min(vibrato_page-1,1)] >= 0)) then
                                      data[vibrato_page] :=
                                      data[vibrato_page] AND $0f+
                                      hex(CHAR(LO(is_environment.keystroke))) SHL 4
                                    else data[vibrato_page] :=
                                         -(Abs(data[vibrato_page]) AND $0f+
                                           hex(CHAR(LO(is_environment.keystroke))) SHL 4);

                          '8'..'F': If (data[vibrato_page] > 0) or
                                       ((data[vibrato_page] = 0) and
                                        (data[min(vibrato_page-1,1)] >= 0)) then
                                      data[vibrato_page] := $7f
                                    else data[vibrato_page] := -$7f;

                          '+': begin
                                 If (data[vibrato_page] < $7f) then Inc(data[vibrato_page]);
                                 nope := FALSE;
                               end;
                          '-': begin
                                 If (data[vibrato_page] > -$7f) then Dec(data[vibrato_page]);
                                 nope := FALSE;
                               end;
                        end;

                     3: Case UpCase(CHAR(LO(is_environment.keystroke))) of
                          '0'..'9',
                          'A'..'F': If (data[vibrato_page] > 0) or
                                       ((data[vibrato_page] = 0) and
                                        (data[min(vibrato_page-1,1)] >= 0)) then
                                      data[vibrato_page] :=
                                      data[vibrato_page] AND $0f0+
                                      hex(CHAR(LO(is_environment.keystroke)))
                                    else data[vibrato_page] :=
                                         -(Abs(data[vibrato_page]) AND $0f0+
                                           hex(CHAR(LO(is_environment.keystroke))));
                          '+': begin
                                 If (data[vibrato_page] < $7f) then Inc(data[vibrato_page]);
                                 nope := FALSE;
                               end;
                          '-': begin
                                 If (data[vibrato_page] > -$7f) then Dec(data[vibrato_page]);
                                 nope := FALSE;
                               end;
                        end;

                   end;

                   If nope then
                     Case vibrato_hpos of
                       1,3: begin
                              If (command_typing = 2) and
                                 NOT (UpCase(CHAR(LO(is_environment.keystroke))) in ['-','+']) and
                                 (vibrato_hpos = 3) then Dec(vibrato_hpos);
                              If (vibrato_page < 255) then Inc(vibrato_page)
                              else If cycle_pattern then vibrato_page := 1;
                            end;
                       2:   If NOT (command_typing = 2) or
                               (UpCase(CHAR(LO(is_environment.keystroke))) in ['-','+']) then
                              begin
                                If (vibrato_page < 255) then Inc(vibrato_page)
                                else If cycle_pattern then vibrato_page := 1;
                              end
                            else Inc(vibrato_hpos);
                     end;
                 end;
           end;
      end;

      If NOT shift_pressed and (is_environment.keystroke = kSPACE) then
        begin
          refresh;
          HideCursor;
          _pip_dest := screen_ptr;
          If (_4op_to_test <> 0) then _macro_preview_init(1,BYTE(NOT BYTE_NULL))
          else _macro_preview_init(1,BYTE_NULL);

          If ctrl_pressed and (is_environment.keystroke = kSPACE) then
            begin
              _pip_loop := TRUE;
              For temp := 1 to 20 do keyoff_loop[temp] := _pip_loop;
            end
          else For temp := 1 to 20 do keyoff_loop[temp] := _pip_loop;

          macro_preview_indic_proc := _preview_indic_proc;
          is_environment.keystroke := WORD_NULL;

          If NOT _force_program_quit then
            Repeat
              // update octave
              For temp := 1 to 8 do
                If (temp <> current_octave) then
                  show_str(30+temp,30,CHR(48+temp),
                           main_background+main_stat_line)
                else show_str(30+temp,30,CHR(48+temp),
                              main_background+main_hi_stat_line);

              If keypressed then
                begin
                  is_environment.keystroke := getkey;
                  Case is_environment.keystroke of
                    kCtLbr:  If shift_pressed then
                               begin
                                 If (songdata.macro_speedup > 1) then
                                   Dec(songdata.macro_speedup);
                                 macro_speedup := songdata.macro_speedup;
                                 reset_player;
                               end
                             else If (_4op_to_test = 0) then
                                    If (current_inst > 1) then
                                      Dec(current_inst);

                    kCtRbr:  If shift_pressed then
                               begin
                                 Inc(songdata.macro_speedup);
                                 If (calc_max_speedup(songdata.tempo) < songdata.macro_speedup) then
                                   songdata.macro_speedup := calc_max_speedup(songdata.tempo);
                                 macro_speedup := songdata.macro_speedup;
                                 reset_player;
                               end
                             else If (_4op_to_test = 0) then
                                    If (current_inst < 255) then
                                      Inc(current_inst);
                  end;

                  If (is_environment.keystroke = kCtLbr) or
                     (is_environment.keystroke = kCtRbr) then
                    begin
                      keyboard_reset_buffer;
                      ShowCStr(centered_frame_vdest,xstart+window_area_inc_x+66,ystart+24+window_area_inc_y,
                               ExpStrL(' ~[SPEED:'+Num2str(tempo*songdata.macro_speedup,10)+#3+']~ ',17,'Í'),
                               macro_background+macro_border,
                               macro_background+macro_hi_text);
                      instrum_page := current_inst;
                      STATUS_LINE_refresh;
                      instr := current_inst;
                      If NOT arp_vib_mode then
                        ShowStr(centered_frame_vdest,xstart+48,ystart,byte2hex(instr),
                                macro_background+dialog_title);
                      refresh;
                    end;

                  If (_4op_to_test <> 0) then
                    _macro_preview_body(LO(_4op_to_test),HI(_4op_to_test),count_channel(pattern_hpos),is_environment.keystroke)
                  else _macro_preview_body(instrum_page,BYTE_NULL,count_channel(pattern_hpos),is_environment.keystroke);

                  If ctrl_pressed and NOT shift_pressed and
                     (is_environment.keystroke = kSPACE) then
                    begin
                      _pip_loop := NOT _pip_loop;
                      For temp := 1 to 20 do keyoff_loop[temp] := _pip_loop;
                      is_environment.keystroke := WORD_NULL;
                    end;

                  If shift_pressed and (is_environment.keystroke = kSPACE) then
                    is_environment.keystroke := WORD_NULL;
                end
              else If NOT (seconds_counter >= ssaver_time) then GOTO _end2 //CONTINUE
                   else begin
                          screen_saver;
                          GOTO _end2; //CONTINUE;
                        end;
_end2:
{$IFDEF __TMT__}
    keyboard_reset_buffer_alt;
{$ELSE}
    emulate_screen;
{$ENDIF}
            until (is_environment.keystroke = kSPACE) or
                  (is_environment.keystroke = kESC);

            If (_4op_to_test <> 0) then _macro_preview_init(0,BYTE(NOT BYTE_NULL))
            else _macro_preview_init(0,BYTE_NULL);
            macro_preview_indic_proc := NIL;
            _pip_dest := ptr_temp_screen;
            ThinCursor;
          end;
{$IFDEF __TMT__}
    keyboard_reset_buffer_alt;
{$ELSE}
    emulate_screen;
{$ENDIF}
      until (is_environment.keystroke = kESC)    or
            (is_environment.keystroke = kAltC)   or
            (is_environment.keystroke = kCtrlO)  or
            (is_environment.keystroke = kF1)     or
            (is_environment.keystroke = kF2)     or
            (is_environment.keystroke = kCtrlF2) or
            (is_environment.keystroke = kF3)     or
            (is_environment.keystroke = kCtrlL)  or
            (is_environment.keystroke = kCtrlS)  or
            (is_environment.keystroke = kCtrlM)  or
            call_pickup_proc or
            call_pickup_proc2;

  _macro_editor__pos[arp_vib_mode] := pos;
  _macro_editor__fmreg_hpos[arp_vib_mode] := fmreg_hpos;
  _macro_editor__fmreg_page[arp_vib_mode] := fmreg_page;
  _macro_editor__fmreg_left_margin[arp_vib_mode] := fmreg_left_margin;
  _macro_editor__fmreg_cursor_pos[arp_vib_mode] := fmreg_cursor_pos;
  _macro_editor__arpeggio_page[arp_vib_mode] := arpeggio_page;
  _macro_editor__vibrato_hpos[arp_vib_mode] := vibrato_hpos;
  _macro_editor__vibrato_page[arp_vib_mode] := vibrato_page;

  If NOT arp_vib_mode then
    begin
      songdata.instr_macros[instr].arpeggio_table := ptr_arpeggio_table;
      songdata.instr_macros[instr].vibrato_table := ptr_vibrato_table;
    end
  else begin
         arpvib_arpeggio_table := ptr_arpeggio_table;
         arpvib_vibrato_table := ptr_vibrato_table;
       end;

  For temp := 1 to 255 do
    begin
      temp_marks[temp] := songdata.instr_names[temp][1];
      songdata.instr_names[temp][1] := ' ';
    end;

  If (Update32(songdata,SizeOf(songdata),0) <> songdata_crc) then
    module_archived := FALSE;

  For temp := 1 to 255 do
    songdata.instr_names[temp][1] := temp_marks[temp];

  HideCursor;
  Move(old_keys,is_setting.terminate_keys,SizeOf(old_keys));
  move_to_screen_data := ptr_screen_backup;
  move_to_screen_area[1] := xstart;
  move_to_screen_area[2] := ystart;
  move_to_screen_area[3] := xstart+81+2+window_area_inc_x;
  move_to_screen_area[4] := ystart+24+1+window_area_inc_x;
  move2screen;

  Case is_environment.keystroke of
    kAltC:   begin
               If (pos in [7,13,20]) then
                 begin
                   copymnu4[13] := copymacr[2];
                   copymnu4[14] := copymacr[4];
                 end
               else begin
                      copymnu4[13] := copymacr[1];
                      copymnu4[14] := copymacr[3];
                    end;

               mn_setting.cycle_moves := TRUE;
               temp := Menu(copymnu4,01,01,copypos4,30,15,15,' COPY OBJECT ');
               copymnu4[13] := copymacr[2];
               copymnu4[14] := copymacr[4];
               If (mn_environment.keystroke <> kESC) then
                 begin
                   copypos4 := temp;
                   clipboard.object_type := tCOPY_OBJECT(temp);
                   Case pos of
                     1..7:   clipboard.mcrtab_type := mttFM_reg_table;
                     8..13:  clipboard.mcrtab_type := mttArpeggio_table;
                     14..20: clipboard.mcrtab_type := mttVibrato_table;
                   end;
                   copy_object;
                 end;
               GOTO _jmp1;
             end;

    kENTER:  If call_pickup_proc2 then
               begin
                 call_pickup_proc2 := FALSE;
                 temp := INSTRUMENT_CONTROL_alt(_source_ins2,'PASTE DATA TO REGiSTERS [iNS_'+
                                                             byte2hex(_source_ins2)+']');
                 If (temp <> 0) then
                   begin
                     _source_ins2 := temp;
                     songdata.instr_data[_source_ins2].fm_data :=
                     songdata.instr_macros[instr].data[fmreg_page].fm_data;
                     songdata.instr_data[_source_ins2].panning :=
                     songdata.instr_macros[instr].data[fmreg_page].panning;
                     songdata.instr_data[_source_ins2].fine_tune :=
                     songdata.instr_data[instr].fine_tune;
                     songdata.instr_data[_source_ins2].perc_voice :=
                     songdata.instr_data[instr].perc_voice;

                     songdata.instr_data[_source_ins2].fm_data.FEEDBACK_FM :=
                     songdata.instr_data[_source_ins2].fm_data.FEEDBACK_FM AND $3f;

                     With  songdata.instr_data[_source_ins2].fm_data do
                       begin
                         KSL_VOLUM_modulator := KSL_VOLUM_modulator AND $c0+
                                                63-KSL_VOLUM_modulator AND $3f;
                         KSL_VOLUM_carrier := KSL_VOLUM_carrier AND $c0+
                                              63-KSL_VOLUM_carrier AND $3f;
                       end;
                   end;
                 GOTO _jmp1;
               end;

    kCtENTR: If call_pickup_proc then
               begin
                 call_pickup_proc := FALSE;
                 temp := INSTRUMENT_CONTROL_alt(_source_ins,'PASTE DATA FROM REGiSTERS [iNS_'+
                                                            byte2hex(_source_ins)+']');
                 If (temp <> 0) then
                   begin
                     _source_ins := temp;
                     temp := songdata.instr_macros[instr].data[fmreg_page].
                             fm_data.FEEDBACK_FM;
                     songdata.instr_macros[instr].data[fmreg_page].fm_data :=
                       songdata.instr_data[_source_ins].fm_data;
                     songdata.instr_macros[instr].data[fmreg_page].
                     fm_data.FEEDBACK_FM := temp AND $0c0+
                       songdata.instr_data[_source_ins].fm_data.FEEDBACK_FM AND $3f;

                     songdata.instr_macros[instr].data[fmreg_page].panning :=
                       songdata.instr_data[_source_ins].panning;
                     songdata.instr_macros[instr].data[fmreg_page].duration :=
                       min(songdata.instr_macros[instr].data[fmreg_page].duration,1);

                     With songdata.instr_macros[instr].data[fmreg_page].fm_data do
                       begin
                         KSL_VOLUM_modulator := KSL_VOLUM_modulator AND $c0+
                                                63-KSL_VOLUM_modulator AND $3f;
                         KSL_VOLUM_carrier := KSL_VOLUM_carrier AND $c0+
                                              63-KSL_VOLUM_carrier AND $3f;
                       end;

                     If (fmreg_page < 255) then Inc(fmreg_page)
                     else If cycle_pattern then fmreg_page := 1;
                   end;
                 GOTO _jmp1;
               end;
    kF2,
    kCtrlS:  begin
               quick_cmd := FALSE;
               If NOT arp_vib_mode then FILE_save('a2f')
               else FILE_save('a2w');
               GOTO _jmp1;
             end;

    kCtrlF2: begin
               quick_cmd := FALSE;
               If NOT arp_vib_mode then FILE_save('a2w');
               GOTO _jmp1;
             end;
    kF3,
    kCtrlL:  begin
               If (pos < 8) then
                 temps := '*.a2i$*.a2f$*.a2b$*.a2w$'+
                          '*.bnk$*.cif$*.fib$*.fin$*.ibk$*.ins$*.sbi$*.sgi$'
               else temps := '*.a2w$';
               quick_cmd := FALSE;
               If NOT (pos < 8) then _arp_vib_loader := TRUE
               else _arp_vib_loader := FALSE;
               If _arp_vib_loader then
                 begin
                   arp_tab_selected := pos in [8..13];
                   vib_tab_selected := pos in [14..20];
                   If NOT arp_vib_mode then
                     begin
                       arpvib_arpeggio_table := ptr_arpeggio_table;
                       arpvib_vibrato_table := ptr_vibrato_table;
                     end;
                 end
               else begin
                      arp_tab_selected := ptr_arpeggio_table <> 0;
                      vib_tab_selected := ptr_vibrato_table <> 0;
                      If NOT (arp_tab_selected or vib_tab_selected) then
                        begin
                          arp_tab_selected := TRUE;
                          vib_tab_selected := TRUE;
                        end;
                    end;
               FILE_open(temps,FALSE);
               update_instr_data(instrum_page);
               GOTO _jmp1;
             end;

    kCtrlO:  begin OCTAVE_CONTROL; GOTO _jmp1; end;

    kCtrlM:  begin
               MACRO_BROWSER((pos < 8),FALSE);
               GOTO _jmp1;
             end;

    kF1:     begin
               If NOT arp_vib_mode then HELP('macro_editor')
               else HELP('macro_editor_(av)');
               GOTO _jmp1;
             end;
  end;
  _pip_loop := FALSE;
end;

procedure MACRO_BROWSER(instrBrowser: Boolean; updateCurInstr: Boolean);
begin
{$IFDEF __TMT__}
  _last_debug_str_ := _debug_str_;
  _debug_str_ := 'ADT2EXT4.PAS:MACRO_BROWSER';
{$ENDIF}
  songdata_crc := Update32(songdata,SizeOf(songdata),0);
  a2w_file_loader(FALSE,NOT instrBrowser,TRUE,FALSE,updateCurInstr); // browse internal A2W data
  If (Update32(songdata,SizeOf(songdata),0) <> songdata_crc) then
    module_archived := FALSE;
end;

end.
