program SoftDDS;
(*
DDS-Funktionsgenerator mit mega8515, R2R-Netzwerk und Billig-MP3-Spieler
als universelle Audio-Quelle
(c) by c't magazin und Carsten Meyer, cm@ctmagazin.de

-- eigenständige Simpel-Version mit AT90S8515, R2R-D/A-Wandler,
   dB-Einstellung nur in 10-dB-Schritten

LCD mit 2x16 Zeichen, für Preset- und Default-Anzeige
5 Taster zur Bedienung, Up/Down, Left/Right, Aux
Steuert MP3-Spieler, die per Widerstands-Netz fernbedienbar sind
Vorliegende Version angepasst für Billigst-MP3-Spieler mit
Myson Century MTM809/CS8822 Chipsatz von EFB/ETT, Braunschweig
oder Yampp Industrial III von Jesper Hansen, www.jelu.se
*)

{$NOSHADOW}
{ $W+ Warnings}            {Warnings off}
{$TYPEDCONST OFF}
{$DEBDELAY}

//Defines aktivieren durch Entfernen des 1. Leerzeichens!

//miniDDS-Anpassungen in einigen I/O-Routinen, Software-DDS-Prozedur
//einen der folgen Prozessoren auswählen:
{$DEFINE atmega8515}        //ATmega8515 mit 16 MHz
{ $DEFINE at90s8515}         //AT90S8515 mit 8 MHz

{$DEFINE minEEPROM}         //TEST: minimale EEPROM-Presets während Entwicklung
{ $DEFINE MenuTest}          //TEST: Keine HW-IO-Routinen, zum Testen der Menüs
{ $DEFINE yi3}         //MP3-Player Yampp Industrial an serieller Schnittstelle

{$IFDEF atmega8515}
Device = mega8515, VCC = 5;
{$ENDIF}
{$IFDEF at90s8515}
Device = 90S8515, VCC = 5;
{$ENDIF}
Import SysTick, LCDPort;


From System Import LongInt;

Define
{$IFDEF at90s8515}
  ProcClock      = 8000000;        {Hertz}
{$ELSE}
  ProcClock      = 16000000;        {Hertz}
{$ENDIF}

  LCDPort        = PortC;
  LCDTYPE        = 44780;
  LCDrows        = 2;              //2 rows
  LCDcolumns     = 16;             //16 chars per line


  SysTick        = 10;              //msec
  StackSize      = $0080, iData;
  FrameSize      = $0060, iData;

Implementation

{--------------------------------------------------------------}
type
  TEditWhich     = (m_fr1, m_fr2, m_fr3, m_fr4, m_fr5, m_fr6, m_fr7, m_frdec, m_patch, m_db, m_wav, m_rpt, m_out, m_brst, m_frequ, m_mv);

{--------------------------------------------------------------}
const
//Wave = Sinus, Dreieck/Sägezahn, Rechteck, Audio 1..99
  c_sinw                     = 0;
  c_triw                     = 1;
  c_squw                     = 2;
  c_audio                    = 3;

//OutputMode Normal,
  c_nrmo                     = 0;
  c_symo                     = 1;
  c_pwro                     = 2;
  c_psymo                    = 3;

{ Keyboard-Interface, Taster und LEDs PortBits }

  m_lastmenu                 = m_rpt;

  DDRAinit                   = %11111111;            {PortA dir }
  PortAinit                  = %10000000;            {PortA, R2R-Netz}

  DDRBinit                   = %11111111;            {PortB dir }
  PortBinit                  = %10001111;            {PortB, MP3-Steuerung}

  DDRCinit                   = %10000000;            {PortC dir }
  PortCinit                  = %10000000;            {PortC, LED PC7}

  DDRDinit                   = %00000000;            {PortD dir }
  PortDinit                  = %11111111;            {PortD, Taster}

  BtnInPortReg               = @PinD;   {Taster-Eingangsport}
  LEDOutPort                 = @PortC;   {LED-Port}

  R2ROutPort                 = @PortA;   {DA-Wandler-Port}
  MPXPort             = @PortB;   {Multiplexer-Port, Bits PB0..PB2}

{miniDDS-Konstanten für Frequenzen, addiert für DDS, 16 MHz/12 DDS-Zyklen}
{$IFDEF atmega8515}
  fhz            : Table[0..7] of LongInt = (12582912, 1258291, 125829, 12583, 1258, 126, 13, 1);
{Dezimalstelle gerundet, nur die ersten 10 benutzt}
  fdhz           : Table[0..15] of LongInt = (0, 1, 2, 3, 5, 6, 7, 8, 10, 12, 0, 0, 0, 0, 0, 0);
{$ENDIF}
{$IFDEF at90s8515}
{miniDDS-Konstanten für Frequenzen, addiert für DDS, 8 MHz/12 DDS-Zyklen}
  fhz            : Table[0..7] of LongInt = (25165824, 2516582, 251658, 25166, 2517, 252, 25, 3);
{Dezimalstelle gerundet, nur die ersten 10 benutzt}
  fdhz           : Table[0..15] of LongInt = (0, 3, 5, 8, 10, 13, 15, 18, 20, 23, 0, 0, 0, 0, 0, 0);
{$ENDIF}

  dBfac          : Table[0..31] of Word = (
{$I dB775mV.txt}
  );

//Sinus-Tabelle für Soft-DDS, *muss* auf Seiten-Anfang liegen
  sinus[@$1f00]  : Table[0..255] of byte = (
  {$I sinus.txt}
  );

//LCDXY-Positionen der Menüs und der zugehörigen Cursor-Position auf dem Display
//Reihenfolge wie EditWhich:
//m_fr1, m_fr2, m_fr3, m_fr4, m_fr5, m_fr6, m_fr7, m_frdec, m_patch, m_db, m_wav, m_rpt, m_out, m_brst, m_frequ, m_mv
  posx           : Table[0..15] of byte = (0, 2, 4, 6, 8, 10, 12, 14, 7, 9, 0, 5, 8, 13, 4, 4);             //###
  cursx          : Table[0..15] of byte = (1, 3, 5, 7, 9, 11, 13, 15, 9, 13, 3, 7, 11, 15, 0, 0);
  posy           : Table[0..15] of byte = (1, 1, 1, 1, 1, 1,  1,  1,  0,  0, 1, 1, 1, 1, 1, 1);

//Lineal     .----.----.----.----.----.----.----.----.----
  Vers1Str                   = 'miniDDS V#2.11';    //Vers1
  Vers2Str                   = 'C. Meyer 03/06';    //Vers2

  HzStr                      = ' Hz';
  dBStr                      = ' dB';
  SinStr                     = 'Sin';
  SquStr                     = 'Sqr';
  TriStr                     = 'Swt';
  EmptyStr                   = '-*-';

  PlayStr                    = 'Play       ';
  WaitStr                    = 'Wait...';

  MemStr                     = 'Memory ';
  PresetStr                  = 'Preset ';
  TerzStr                    = 'TerzFr ';
  AudioStr                   = 'Audio  ';
  FrequStr                   = 'Frequency Hz    ';

  OptStr                     = 'Wav Rpt         ';

  high                       = true;
  low                        = false;

  b_SCLK                     = 0; //Takt für 4094
  b_SDATA                    = 1; //Daten für 4094
  b_STROBE                   = 2; //4094 SR Strobe


//Preset: Terzfrequenzen
//20, 25, 31,5, 40, 50, 63, 80, 100, 125, 160, 250, 315, 400, 500,
//630, 800, 1k, 1,25k, 1,6k, 2k, 2,5k, 3,15k, 4k, 5k, 6,3k, 8k, 10k, 12.5k, 16k, 20k
  TerzArray      : Table[0..31] of integer =
  (
  1000,   20,      25,     31,      40,     50,      63,     80,
  100,    125,     160,    200,     250,    315,     400,    500,
  630,    800,     1000,   1250,    1600,   2000,    2500,   3150,
  4000,   5000,    6300,   8000,    10000,  12500,   16000,  20000
  );

//Default-EEPROM-Werte:
{$EEPROM}
structconst

{$IFDEF minEEPROM}
// m_wav, m_rpt, m_out, m_brst, m_db, -,-,-, m_fr1, m_fr2, m_fr3, m_fr4, m_fr5, m_fr6, m_fr7, m_frdec
  EEPatchArray   : array[0..51] of Byte =
  (
  0, 0, 0, 1, 0, 0, 0, 0,    //m_frequ
  0, 30, 0, 0, 70,      //Wav m_rpt m_out m_brst m_db
  0, 0, 0, 1, 0, 0, 0, 1,    //m_frequ
  0, 30, 0, 0, 70,      //Wav m_rpt m_out m_brst m_db
  0, 0, 0, 1, 0, 0, 0, 2,    //m_frequ
  0, 30, 0, 0, 70,      //Wav m_rpt m_out m_brst m_db
  0, 0, 0, 1, 0, 0, 0, 3,    //m_frequ
  0, 30, 0, 0, 70      //Wav m_rpt m_out m_brst m_db
  );
{$ELSE}
{$I mem-70dB.txt}
{$ENDIF}
  EEPwrGain :byte = 20;   // 20 dB PowerAmp-Nachverstärkung
  
{--------------------------------------------------------------}

var
{$EEPROM}

{$DATA} {Schnelle Register-Variablen}
  i, k           : Byte;
  m, DDSL, DDSM, DDSH  : Byte;

{$IDATA}  {Langsamere SRAM-Variablen}

  dss_cmd        : word;
  wave_cmd       : word;
  Out4094: Byte; //Zwischenspeicher für 4094 SR an PortB miniDDS
  BtnInState     : Byte;  //Sample-Wert der Panel-Tasten

  b_TasteAuf[@BtnInState, 2] : bit; {Taste Up}
  b_TasteAb[@BtnInState, 3]  : bit; {Taste Down}
  b_TasteLinks[@BtnInState, 4]: bit;
  b_TasteRechts[@BtnInState, 5]: bit;
  b_TasteAux[@BtnInState, 7] : bit; {Bit 7 ist Taste Aux, separat}

  b_LEDaux[LEDOutPort, 7]    : bit; {Bit 7 ist LED, separat}
  b_ExtOnMP3Power[MPXPort, 3]: bit; {Bit 0 ist PNP-Schalttransistor}

  EditWhich, DispWhich: TEditWhich;
  CurItemNumber,
  DisplayValue, EditValue,
  ItemUpperLimit, ItemLowerLimit, x, y, {x,y Koordinaten LCD}
  GainOffset,                    //0 oder 20 für NormOut/SymOut oder PowerOut/PowerSym
  digits,
  BtnTime, BtnTime2,
  BurstCount     : Byte;
  prime, BurstPrime, Modified, aBool, PresetOn, MP3isOn: boolean;
  MP3repeatBset  : Boolean;      // Repeat-Punkt B gesetzt?

  PwrGain        : byte; //Nachverstärkung extern Default (kein Edit-Wert!)
  MemoryNum       : byte;
  MP3Track       : byte;

//Edit-Item-Reihenfolge
  EditArray      : Table[0..15] of Byte;
  Edit1[@EditArray]    : byte;

  Frequ1[@Edit1] : byte;      // 1 Mhz
  Frequ2[@Frequ1+1]    : byte;       // 100kHz
  Frequ3[@Frequ1+2]    : byte;
  Frequ4[@Frequ1+3]    : byte;
  Frequ5[@Frequ1+4]    : byte;
  Frequ6[@Frequ1+5]    : byte;
  Frequ7[@Frequ1+6]    : byte;       //1 Hz
  FrequDez[@Frequ1+7]  : byte;     //0.1 Hz

  Wave[@Edit1+8] : byte;
  MP3sec[@Wave+1]      : byte;
  OutputMode[@Wave+2]  : byte;
  BurstMode[@Wave+3]   : byte;
  AttnStep[@Wave+4]     : byte; //0...100= -70 ... +30dB
  PresetNum[@Wave+5]     : byte;
  SaveArray      : Table[0..15] of Byte;
  Save1[@SaveArray]    : byte;

  LevelStr       : string[7];
  FreqStr        : String[8];
  MP3repeatTimer : SysTimer;
  BurstTimer     : SysTimer8;
  MP3runningTimer, MP3runningSeconds: Byte;
  MP3currenttrack: Byte;

const
//Anpassen bei Änderungen der Reihenfolge: Letzter - Erster Eintrag
  EditArrayLen               = 1 + @AttnStep - @EditArray;

{###########################################################################}

procedure OnSysTick;
begin
  inc(MP3runningTimer);
  if MP3runningTimer = 100 then
    MP3runningTimer:= 0;
    inc(MP3runningSeconds);
    if MP3runningSeconds = MP3sec then
      MP3runningSeconds := 0;
    endif;
  endif;
end;
{$NOSAVE}

{###########################################################################}
//DDS-Funktionen

{$IFDEF MenuTest}
procedure SetupDSS;  //Freqenz und Pegel einstellen
begin
end;
procedure SetLevelDDS;  //Sende alle Daten
begin
end;
procedure SendDDS;  //Sende ein Wort an den DDS-Chip
begin
end;
procedure SendSR;  //Sende MP3- und SwitchState an den 4094 oder Ausgangsport
begin
end;
procedure miniDDS;
begin
end;
{$ELSE}
{$I MP3source-HW.pas}
{$ENDIF}

{###########################################################################}
//EEPROM-Routinen

procedure PresetCopyFromROM;
//Frequenz aus ROM-Terz-Tabelle (Integer!) holen
begin
//Wert in String zwecks Auswertung (raffiniert!)
  FreqStr:= inttostr(gettable(TerzArray, PresetNum) : 7);
  FreqStr[8]:= #48;   //Zehntel
  for i := 0 to 7 do
    k:= byte(FreqStr[i + 1]);
    if k = 32 then  //führende Leerzeichen?
      k := 48;
    endif;
    settable(EditArray, i, k - 48);
  endfor;
end;

procedure PresetSave;
//Sichert aktuelles EditArray bei Wechsel auf Memory
begin
  CopyBlock(@Frequ1, @Save1, 16);
end;

procedure PresetRestore;
//Stellt EditArray nach Wechsel von Memory auf Presets wieder her
begin
  CopyBlock(@Save1, @Frequ1, 16);
end;

procedure PatchCopyFromEE;
//Frequenz und Settings aus EEPROM holen
var myPatchAdr: Word;
begin
  myPatchAdr :=  word(MemoryNum)*EditArrayLen;
  for i := 0 to EditArrayLen - 1 do
    settable(EditArray, i, (EEPatchArray[myPatchAdr + word(i)]));
  endfor;
end;

procedure PatchCopyToEE;
//Frequenz und Settings in EEPROM speichern
var myPatchAdr: Word;
begin
  myPatchAdr := word(MemoryNum)*EditArrayLen;
  for i := 0 to EditArrayLen - 1 do
    EEPatchArray[myPatchAdr + word(i)]:= gettable(EditArray, i);
  endfor;
end;

{###########################################################################}
//Menü-Prozeduren

procedure LCD1xy;
begin
  LCDxy(x, y);
end;

procedure SetPos;
begin
  i:= ord(DispWhich);
  x:= gettable(posx, i);
  y:= gettable(posy, i);
  LCD1xy;
end;

procedure SetCursor;
begin
  i:= ord(EditWhich);
  x:= gettable(cursx, i);
  y:= gettable(posy, i);
  LCD1xy;
//Cursor-Zeichen "<" ist #0
  LCDout(#0);
end;


procedure LCD1x0y0;
begin
  LCDhome;
  mdelay(1); //sonst manchmal Fehlfunktionen
end;

procedure LCD1x0y1;
begin
  x:= 0;
  y:= 1;
  LCD1xy;
end;

{$I buttons.pas}
{$I mp3control.pas}


procedure CheckItemLimits;
//EditValue eingrenzen
begin
  if EditValue = $ff then
    EditValue := 0;
  endif;
  if EditValue > ItemUpperLimit then
    EditValue := ItemUpperLimit;
  endif;
  if EditValue < ItemlowerLimit then
    EditValue := ItemlowerLimit;
  endif;
end;

procedure WriteItem;
//### NEU
//einzelnen Wert DisplayValue darstellen
begin
//Zahlenausgabe ein- bis zweistellig, ohne führender Null:
//Äquivalent zu write(lcdout, ByteToStr(DisplayValue:digits));
  if DisplayValue > 9 then
    digits:=2;
  endif;
  if digits > 1 then
    k:= DisplayValue;
    k:= (k div 10);
    if k=0 then
      LCDout(#32);
    else
      LCDout(char(k + 48));
    endif;
  endif;
  k:= DisplayValue mod 10;
  LCDout(char(k + 48));
end;

procedure WriteWave;
//Wellenform ausschreiben
begin
  DispWhich:= m_wav;
  setPos;
  case Wave of
    c_sinw :
        WriteLCD(@SinStr);
   |
    c_triw :
        WriteLCD(@TriStr);
   |
   c_squw :
        WriteLCD(@SquStr);
   |
  else
    WriteLCD(@EmptyStr);
  endcase;
end;


procedure ShowFrequSpaced;
//Frequenz-Array (Teil von EditArray) mit Leerzeichen
//zwischen einzelnen Ziffern darstellen
begin
  LCD1x0y0;
  WriteLCD(@FrequStr);
  LCD1x0y1;
  for i:= 0 to 7 do
    k:= gettable(EditArray, i);
    LCDout(char(k + 48));
    if i = 6 then
      LCDout(#46); //Dezimalpunkt nach 7. Stelle
    else
      LCDout(#32);
    endif;
  endfor;
end;


procedure WriteFrequency;
//Frequenz-Array (Teil von EditArray) darstellen
var blank: boolean;
begin
  DispWhich:= m_frequ;
  setpos;
  blank := true;
  for i:= 0 to 6 do
    DisplayValue:= gettable(EditArray, i);
    if DisplayValue <> 0 then
      blank:= false;
    endif;
    if (DisplayValue = 0) and blank then
      LCDout(#32);
    else
      LCDout(char(DisplayValue + 48));
    endif;
  endfor;
  LCDout(#46); //Dezimalpunkt nach 7. Stelle
  DisplayValue:= FrequDez;
  LCDout(char(DisplayValue + 48));
  WriteLCD(@HzStr);
end;

procedure WriteLevelmV;
//m_db-Wert in AttnStep in mV umrechnen (nach mV-Tabelle) und darstellen
var blank: boolean;
  dBtab          : byte;
  Prefix         : char;
//mV aus m_db ausrechnen
begin
  DispWhich:= m_mv;
  SetPos;

  dBtab:= AttnStep + 10;   //Anpassung für Mini-DDS
//  dBtab := AttnStep + GainOffset + 10; // für AD9833-DDS mit LM1972

  i:= dBtab mod 20;
  k:= ((dBtab + 10) div 20) + 2;  //Komma-Position ermitteln
  Prefix:= 'm';   // für mV
  LevelStr:= inttostr(gettable(dBfac, i) : 6);

  //hier: 10...110 = -70 ... +30dB
  //eigener Regelbereich 0...80 = -70 ... +10dB
  case dBtab of
    10..29  :      //-70..-51
              k:= k + 3;
              insert('.', LevelStr, k);
              Prefix:= #228;   // für uV
            |
    30..89  :     //-50..+9
              insert('.', LevelStr, k);
            |
    90..109 :     //+10..+29
              insert('.', LevelStr, 4);
              Prefix:= #32;   //kein Prefix
            |
  endcase;
  LCDout(#32);   //Leerzeichen
  LCDout(#32);   //Leerzeichen
  write(lcdout, LevelStr);
  LCDout(#32);   //Leerzeichen
  LCDout(Prefix);
  LCDout(#86);
end;

procedure WriteLeveldB;
//m_db-Wert AttnStep ausschreiben
var dBval: Integer;
begin
  DispWhich:= m_db;
  SetPos;
  //0...100 = -70 ... +30dB
  //eigener Regelbereich 0...80 = -70 ... +10dB
  dBval:= integer(AttnStep) - 70;
  write(lcdout, IntToStr(dBval : 4));
  WriteLCD(@dBStr);
end;


procedure WriteMP3trackTime;
//Wave sowie Message, Spielzeit seit Repeat-Start ausschreiben,
//sofern MP3-Player läuft
begin
  if MP3isOn then
    y:= 1;
    x:= 0;    // nur für Position
    LCD1xy;
    WriteLCD(@PlayStr);
    DisplayValue:= MP3runningSeconds;
    WriteItem;
    LCDout(#58);   //Doppelpunkt
    digits:= 1;
    DisplayValue:= MP3runningTimer div 10;
    WriteItem;
    LCDout(#48);  //Null anhängen
    digits:= 2;
  else
    LCDclrEOL;
  endif;
end;

procedure MP3waitMessage;
//Warte-Meldung bei Trackwechsel und Einschalten/Initialisieren des MP3-Players
begin
  y:= 1;
  x:= 0;    // nur für Position
  LCD1xy;
  WriteLCD(@WaitStr);
  LCDclrEOL;
end;

procedure ShowOptionsLower;
//Alle Optionen (Teil des EditArray, vier Werte) darstellen
begin
  WriteWave;
  LCDout(#32);   //Leerzeichen
  DispWhich:= m_rpt;
  setPos;
  DisplayValue:= MP3sec;
  WriteItem;
  LCDclrEOL;   //Leerzeichen
{
    WriteOutputMode;
    DispWhich:= m_brst;
    setPos;
    DisplayValue:= BurstMode;
    digits:= 1;
    WriteItem;
    LCDout_M(#48);   //Null
    LCDout_M(#32);   //Leerzeichen
    digits:= 2;
}
end;

procedure ShowOptions;
//Überschrift und alle Optionen darstellen
begin
  LCD1x0y0;
  WriteLCD(@OptStr);
  ShowOptionsLower;
end;

procedure ShowDefaultUpper;
//m_patch/Preset-Nummer und Pegel ausschreiben
begin
  DispWhich:= m_patch;
  digits:= 2;
  if PresetOn Then
    DisplayValue:= PresetNum;
    if PresetNum > 31 then
      DisplayValue:= PresetNum-31;
      LCD1x0y0;
      WriteLCD(@AudioStr);
    else
      DisplayValue:= PresetNum;
      LCD1x0y0;
      if PresetNum = 0 then
        WriteLCD(@PresetStr);
      else
        WriteLCD(@TerzStr);
      endif;
    endif;
  else
    LCD1x0y0;
    WriteLCD(@MemStr);
    DisplayValue:= MemoryNum;
  endif;
  WriteItem;
  LCDout(#32);
  WriteLeveldB;
  SetCursor;
end;

procedure ShowDefaultLower;
//Darstellung der unteren Zeile Hauptmenü: Frequenz, Pegel in mV oder Spielzeit
begin
  LCD1x0y1;
  LCDclrEOL;
  if EditWhich = m_db then
//    WriteOutputMode1;
    WriteLevelmV;
  else
    if not MP3isOn then
      WriteWave;
      WriteFrequency;
    else
      WriteMP3trackTime;
    endif;
  endif;
end;

procedure ShowDefault;
//komplettes Hauptmenü anzeigen
begin
  ShowDefaultUpper;
  ShowDefaultLower;
end;

procedure SetupMP3;
//MP3-Spieler initialisieren und Track anfahren
begin
  if PresetNum > 31 then // Audio-File gewünscht
    MP3Track := PresetNum-31;
    if (not MP3isOn) then
      MP3waitMessage;
      MP3on;
    endif;
    if MP3isOn then
      if MP3Track <> MP3currenttrack then
        setpos;
        MP3waitMessage;
        MP3gotoTrack;
      endif;
      if EditWhich = m_patch then
        WriteMP3trackTime;
      endif;
    endif;
  else
    if MP3isOn then   // wieder Wave, MP3 ausschalten
      MP3off;
      ShowOptionsLower;
      SetCursor;
    endif;
  endif;
end;

{
procedure BurstGen;
//Burst-Generierung per Software hier, während auf Tastatureingabe gewartet wird
begin
  if BurstMode <> 0 then
    if isSysTimerZero(BurstTimer) then
      setSystimer(BurstTimer, 1);
      dec(BurstCount);
      if BurstCount = 0 then
        dss_cmd:= c_ddsresetcmd;
        SendDDS;
        BurstCount:= BurstMode + 1;
        BurstPrime:= true;
      endif;
    endif;
    if BurstCount = 1 then
      if BurstPrime then
        dss_cmd:= wave_cmd;
        SendDDS;
        BurstPrime:= false;
      endif;
    endif;
  endif;
end;
}



{###########################################################################}


procedure initall;
//nach Reset aufgerufen
begin
  DDRA:=  DDRAinit;            {PortA dir}
  PortA:= PortAinit;           {PortA}
  DDRB:=  DDRBinit;            {PortB dir}
  PortB:= PortBinit;           {PortB}
  DDRC:=  DDRCinit;            {PortC dir}
  PortC:= PortCinit;           {PortC}
  DDRD:=  DDRDinit;            {PortD dir}
  PortD:= PortDinit;           {PortD}

  i:= gettable(sinus, 1);        //damit für Compiler bekannt

  LCDclr;
  LCDcursor(false, false);
  LCDCharSet(#0, $02, $06, $0E, $1E, $0E, $06, $02, $00); {"<" Cursor}

  WriteLCD(@Vers1Str);
  LCD1x0y1;
  WriteLCD(@Vers2Str);
  mdelay(1000);

  MemoryNum:= 0;
  PatchCopyFromEE;       // Optionen-Defaults
  PresetNum:= 0;

  BtnTime:= 40; // Initial timer value
  BtnTime2:= 10; // Anzahl Durchläufe bis fast forward

  PwrGain:=EEPwrGain;

  PresetOn:= true;

  b_ExtOnMP3Power:= high;
  LCDclr;
  Modified:= false;
  EnableInts;
  MP3off;
  prime:= false;
{
  BurstCount:= 1;
  setSystimer(BurstTimer, 1);
}
  SetLevelDDS;
end;

{###########################################################################}

begin
  Initall;
  EditWhich:= m_patch;
  ShowDefault;
//Hauptschleife, wird bei jedem Druck eines Aux- oder Navi-Buttons durchlaufen
//sonst innerhalb der Up-Down-Button-Schleife
  loop
    SetLevelDDS;
    CurItemNumber:= ord(EditWhich);
    if EditWhich > m_patch then    //m_patch, m_db überspringen
      CurItemNumber:= CurItemNumber - 2;
    endif;
    EditValue:= gettable(EditArray, CurItemNumber);
    ItemLowerLimit:= 0;
    ItemUpperLimit:= 9;
    digits:= 2;
    case EditWhich of
      m_patch        :
                       ItemUpperLimit:= 41;
                       BtnTime:= 40; //kurz stehenbleiben bei Autorepeat
                       if PresetOn then
                         EditValue:= PresetNum;
                       else
                         EditValue:= MemoryNum;
                       endif;
                       ShowDefault;
                     |
      m_dB           :
                       ItemLowerLimit:= 11;   // -59 dB
                       ItemUpperLimit:= 80;   // +10 dB eigener Regelbereich
                       EditValue:= AttnStep;
                       Showdefault;
                     |
      m_fr1..m_frdec :
                       digits:= 1;
                       ShowFrequSpaced;
                     |
      m_wav          :
                       ItemUpperLimit:= 2;
                       ShowOptions;
                     |

      m_rpt          :
                       ItemLowerLimit:= 1;
                       ItemUpperLimit:= 99;
                       ShowOptions;
                     |
{      m_out          :
                       ItemUpperLimit:= 3;
                       ShowOptions;
                     |
      m_brst         :
                       LCD1x0y0;
                       ShowOptions;
                     |  }
    endcase;
    SetCursor;
    SlowRepeatRelease; // auf Loslassen oder Autorepeat warten
    Modified:= false;
//Up-Down-Unterschleife
    repeat
      if UpDownbutton then
        if not b_TasteAuf then
          inc(EditValue);
        endif;
        if not b_TasteAb then
          dectolim(EditValue, 0);
        endif;
        Modified:= true;
        CheckItemLimits;
        DispWhich:= EditWhich;
        SetPos;
        case EditWhich of
          m_patch        :
                           if PresetOn then
                             PresetNum:= EditValue;
                             if PresetNum < 32 then
                               PresetCopyFromROM;
                             endif;
                           else
                             MemoryNum:= EditValue;
                             PatchCopyFromEE;
                           endif;
                           ShowDefaultUpper;
                           SetLevelDDS; // Pegel neu berechnen für Anzeige
                           SetupMP3;
                           ShowDefaultLower; //nochmal wg. wait
                           Modified:= false;    //hier wird kein Wert verändert
                         |
          m_db           :
                           AttnStep:= EditValue;
                           ShowDefault;
                         |
          m_fr1..m_frdec :
                           // erste acht Bytes im EditArray sind Frequ.
                           settable(EditArray, byte(EditWhich), EditValue);
                           DisplayValue:= EditValue;
                           WriteItem;
                         |
          m_wav          :
                           Wave:= byte(EditValue);
                           WriteWave;
                         |
          m_rpt          :
                           MP3sec:=  EditValue;
                           DisplayValue:= EditValue;
                           WriteItem;
                         |
{          m_out          :
                           OutputMode:= byte(EditValue);
                           WriteOutputMode;
                         |
          m_brst         :
                           BurstMode:=  EditValue;
                           DisplayValue:= EditValue;
                           digits:= 1;
                           WriteItem;
                         |   }
        endcase;
        SetLevelDDS;
        FastRepeatRelease;
//      else
      endif;
//      BurstGen;
      if Modified then
        {neuen Patch speichern}
        if not PresetOn then
          PatchCopyToEE;
        endif;
      endif;
      MP3checkRepeat;
      SetupMP3;
      if not MP3ison then
        miniDDS;
      endif;
    until NaviButton;

    if not b_TasteLinks then
      if EditWhich = m_patch then
        if not MP3isOn then
          EditWhich:= m_frdec;
        endif;
      else
        EditWhich:= pred(EditWhich);
      endif;
    endif;
    if not b_TasteRechts then
      inc(EditWhich);
      if EditWhich > m_LastMenu then
        EditWhich:= m_LastMenu;
      endif;
    endif;
    if not b_TasteAux then
      if PresetOn then
        PresetOn:= false;
        b_LEDaux := low;
        PresetSave;
        PatchCopyFromEE;
        PresetNum:=0;
      else
        PresetOn:= true;
        b_LEDaux := high;
        PresetRestore;
      endif;
      MP3off;
    endif;
  endloop;
end SoftDDS.

