library MXDRVm;

uses
  Windows,SysUtils,Classes, _MXDRVm_const,_MXDRVm_OPMEmu,_MXDRVm_LZX043;

{$R *.res}

//{$DEFINE UseDebugDriver} // 正式公開時は必ずコメントアウトすること。

type
  TPlayInfo=record
    fPlayTimems:double;
    TotalClock,MesureClock:DWORD;
  end;

type
  TMXDRVmDLL = class
  private
    { Private 宣言 }
    OPMVoice: array[0..$FF] of TOPMVoice;

    ToneTable: array[0..$ff] of Byte;
    SlottoTL: array[0..15,0..3] of boolean;
    CarrierSlot: array[0..7] of byte;
    OPMVolTbl: array[0..15] of byte;
    PCMVolTbl: array[0..$7f] of byte;
    ppFreqTable:array[0..ppFreqMax-1] of integer;
    ppConvCalced:boolean;
    ppConvPosTables:array[0..ppFreqMax-1] of PIntegerArray;
    ppConvModTables:array[0..ppFreqMax-1] of PIntegerArray;
    ppVolumeTable:array[0..16] of integer;

    Plus17Mode:boolean;
    MarcuryVolume:integer;

    ADPCM: array[0..ADPCMCount] of TADPCM;
    NowPCMRate:dword;

    procedure WriteDebugLog(msg:string);
    procedure InfomationVisible(MesStr:string);
    procedure MDXOPMRegisterInit;
    procedure OPMVoiceInit;
    procedure SetOPMVoice_V210(Ch:byte);
    procedure SetOPMVoice_V211(Ch:byte);
    procedure SetOPMNoteNumber_V210(Ch:byte;Note:LongInt);
    procedure SetOPMNoteNumber_V211(Ch:byte;Note:LongInt);
    procedure SetOPMNoteon_V210(Ch:byte;Note:LongInt);
    procedure SetOPMNoteon_V211(Ch:byte;Note:LongInt);
    procedure SetOPMVolume_V210(Ch:byte);
    procedure SetOPMVolume_V211(Ch:byte);
    procedure SetADPCMMode_V210(Ch:byte;EnabledNoteon:boolean);
    procedure SetADPCMMode_V211(Ch:byte;EnabledNoteon:boolean);
    procedure SetOPMMPInit_V211(Ch:byte);
    procedure SetOPMMAInit_V211(Ch:byte);
    function  GetMMLCommand(Ch:byte):boolean;
    procedure MMLCompile_V210;
    procedure MMLCompile_V211;
    procedure MMLAnalize_V210(Ch:byte;EnabledNoteon:boolean);
    procedure MMLAnalize_V211(Ch:byte;EnabledNoteon:boolean);
    procedure MMLAnalizeForMesure(Ch:byte);
    procedure MMLCheckForSeek;
    procedure MMLCheckForMesure;
    procedure MMLMesure;
    procedure ProcessSLFO_V210;
    procedure ProcessSLFO_V211;
    procedure ProcessFadeout;
    procedure CheckppAllChannel;
    procedure CalcPCM8ppTable;
    function  RunPCM8pp_V211:longword;
    procedure MMLInsideTrap(FadeoutEnabled:boolean;FadeoutCount:integer);
  public
    MDX:TMDX;
    MMLChannel: array[0..15] of TMMLChannel;
    TransTempo:integer;
    procedure Init(PCMRate:integer);
    function MDXLoad(MDXFilename:string):boolean;
    function PDXLoad(PDXFilename:string):boolean;
    procedure RefTempo;
    procedure MMLSeek(SeekClock:integer);
    procedure SetMute(Ch:byte;MuteFlag:boolean);
    procedure FreeMemory;
    function GetRealVolume(ch:integer):byte;
    procedure SetOPMNoteoff(Ch:byte);
    procedure SetADPCMNoteoff(Ch:byte);
  end;

var
  MXDRVmDLL:TMXDRVmDLL;
  NowDriverVersion:integer;
  InfomationMessage:string;
  PlayInfo:TPlayInfo;
  MXDRVmEnabled:boolean;

var
  ADPCMSRCMode:integer;

// -----------------------------------------------
// Private
// -----------------------------------------------

function WaveFuncTimeout:longword; export; cdecl;
begin
  Result:=MXDRVmDLL.RunPCM8pp_V211;
end;

procedure TimerBtimeout; export; cdecl;
begin
  if X68Sound_OpmPeek=2 then begin
    inc(PlayInfo.TotalClock,1);
    if NowDriverVersion=MXDRVDriverVersion210 then MXDRVmDLL.MMLCompile_V210;
    if NowDriverVersion=MXDRVDriverVersion211 then MXDRVmDLL.MMLCompile_V211;
    with PlayInfo do begin
      fPlayTimems:=fPlayTimems+(($ff-integer(MXDRVmDLL.MDX.Tempo)) shl (10-6))/TimerBModify;
    end;
  end;
  X68Sound_OPMSet($14,32+16+8+2);
end;

procedure TMXDRVmDLL.WriteDebugLog(msg:string);
var
  Filename:string;
  T:TextFile;
begin
  Filename:='MDXError.log';
  AssignFile(T,Filename);
  if FileExists(Filename)=False then
    Rewrite(T)
    else
    Append(T);
  Writeln(T,msg);
  Flush(T);
  CloseFile(T);
end;

procedure TMXDRVmDLL.InfomationVisible(MesStr:string);
begin
  writedebuglog(messtr);
  InfomationMessage:=MesStr;
end;

function TMXDRVmDLL.MDXLoad(MDXFilename:string):boolean;
var
  DummyTitle:string;
  Ch:byte;
  PartNo,Session:integer;
  MDXData:array of byte;
  MDXDataPos:integer;
  TmpByte:byte;
  Add:dword;
  procedure MDXLoadError(mes:string);
  begin
    InfomationVisible('MDXError.'+mes);
  end;
  procedure LoadMDXData(Filename:string);
  var
    MDXFile:TFileStream;
  begin
    MDXFile:=TFileStream.Create(Filename,fmOpenRead or fmShareDenyNone);
    MDX.FileSize:=MDXFile.Size;
    SetLength(MDXData,MDX.FileSize+1);
    MDXFile.ReadBuffer(MDXData[0],MDX.FileSize);
    MDXFile.Free;
    MDXDataPos:=0;
  end;
  function ReadByte:byte;
  begin
    if MDXDataPos>=MDX.FileSize then begin
      MDXLoadError('MDXReadByte:OverPointer');
      Result:=$00;
      end else begin
      Result:=MDXData[MDXDataPos];
    end;
    inc(MDXDataPos);
  end;
  function ReadWord(pos:integer):word;
  begin
    MDXDataPos:=pos;
    if (MDXDataPos+1)>=MDX.FileSize then begin
      MDXLoadError('MDXReadWord:OverPointer');
      Result:=$00;
      end else begin
      Result:=(word(MDXData[MDXDataPos+0]) shl 8)+word(MDXData[MDXDataPos+1]);
    end;
    inc(MDXDataPos,2);
  end;
  procedure AutoDecordLZX;
  var
    unLZXbuf:array of byte;
    LZXOffset,unLZXSize:integer;
  begin
    LZXOffset:=MDXDataPos;
    unLZXSize:=GetunLZXSize(MDXData,LZXOffset);
    if unLZXSize<>0 then begin
      SetLength(unLZXbuf,unLZXSize+1);
      LZXdecord(MDXData,LZXOffset,unLZXbuf);
      MDX.FileSize:=LZXOffset+unLZXSize;
      SetLength(MDXData,MDX.FileSize+2);
      MoveMemory(@MDXData[LZXOffset],@unLZXbuf[0],unLZXSize+1);
    end;
  end;
begin
  Result:=False;

  with MDX do begin
    // Fileopen
    if FileExists(MDXFilename)=False then begin
      InfomationVisible('NotFound '+MDXFilename);
      MDX.MaxChannel:=8;
      for Ch:=0 to 15 do begin
        with MMLChannel[Ch] do begin
          Enabled:=False;
        end;
      end;
      exit;
    end;
    LoadMDXData(MDXFilename);

    // Title Structure Read
    SetLength(DummyTitle,$ff);
    TmpByte:=ReadByte;
    if TmpByte=0 then begin // 先頭が０というのはおかしい（タイトルがない時は$0dのはず）
      MDXLoadError('先頭バイトが$00です。');
      exit;
    end;
    Add:=0;
    while (TmpByte<>$0d) do begin
      if Add<$ff then // ２５５文字以上のタイトルは切り捨てる
        DummyTitle[Add+1]:=char(TmpByte);
      TmpByte:=ReadByte;
      inc(Add);
      if Add>1024 then Add:=1024; // 1KB以上のタイトルはおかしい
    end;
    if Add<$ff then
      SetLength(DummyTitle,Add)
      else
      SetLength(DummyTitle,$ff);

    if ReadByte<>$0a then begin // タイトル終了時、１文字目に $0a以外はおかしい
      MDXLoadError('タイトル終了が$0a,1a以外です。');
      exit;
    end;
    if ReadByte<>$1a then begin // タイトル終了時、２文字目に $1a以外はおかしい
      MDXLoadError('タイトル終了が$0a,1a以外です。');
      exit;
    end;

    // PCMFilename Structure Read
    TmpByte:=ReadByte;
    if TmpByte=$00 then begin
      end else begin
      Add:=0;
      while (TmpByte<>$00) do begin
        TmpByte:=ReadByte;
        inc(Add);
        if Add>=127 then begin // 127文字以上のＰＤＸファイル名はありえない
          MDXLoadError('PDXファイル名が127文字以上です。');
          exit;
        end;
      end;
    end;

    // Check LZH Header
    Segment:=MDXDataPos;
    AutoDecordLZX;
    if MDXData[FileSize-1]=$0F then begin // LZXで欠け落ちたデータを補完
      inc(FileSize,4);
      SetLength(MDXData,FileSize+1);
      MDXData[MDX.FileSize-4]:=$0F;
      MDXData[MDX.FileSize-3]:=$0F;
      MDXData[MDX.FileSize-2]:=$0F;
      MDXData[MDX.FileSize-1]:=$0F;
    end;

    // Segment Set
    Segment:=MDXDataPos;

    // VoiceOffset Read
    VoiceOffset:=ReadWord(Segment);

    // MMLOffset Read
    for Ch:=0 to 15 do begin
      MMLOffset[Ch]:=ReadWord(Segment+dword(Ch)*2+$2);
    end;
    if MMLOffset[0]=$23 then MMLOffset[0]:=$22; // こうの氏作MS-DOS用mxdrv2.06+3,1993.7.5版対策

    // Voice Struct Read
    OPMVoiceInit;
    MDXDataPos:=Segment+VoiceOffset;
    while (MDXDataPos+3+24)<=FileSize do begin
      with OPMVoice[ReadByte] do begin
        if Enabled=True then begin // 音色の多重定義
          ReadByte;
          ReadByte;
          for Session:=0 to 5 do begin
            for PartNo:=0 to 3 do begin
              ReadByte;
            end;
          end;
          end else begin
          Enabled:=True;
          Sync:=True;
          AF:=ReadByte;
          Slot:=ReadByte;
          for Session:=0 to 5 do begin
            for PartNo:=0 to 3 do begin
              Part[PartNo,Session]:=ReadByte;
            end;
          end;
        end;
      end;
    end;

    // MML Channel Parametor Init.
    for Ch:=0 to 15 do begin
      with MMLChannel[Ch] do begin
        SetLength(Buffer,0);
        Enabled:=False;
        MMLSize:=0;
      end;
    end;

    // MML Struct Read  and  Channel Struct Initialize.
    MDXDataPos:=Segment+MMLOffset[0];
    if ReadByte=$e8 then begin
      MDX.MaxChannel:=15;
      ExtendPCM8:=True;
      end else begin
      MDX.MaxChannel:=8;
      ExtendPCM8:=False;
    end;

    if MMLOffset[MDX.MaxChannel]>=VoiceOffset then begin // ＭＭＬより前に VoiceData があるのはおかしい
      MDXLoadError('MMLより前に音色定義があります。');
      exit;
    end;

    for Ch:=0 to MDX.MaxChannel do begin
      if (Segment+MMLOffset[Ch])>dword(FileSize) then begin // オフセットがファイルサイズを超えるのはおかしい
        MDXLoadError('MMLSizeがFileSizeを超えました。');
        exit;
      end;
      with MMLChannel[Ch] do begin
//        MMLSize:=MDX.FileSize-MMLOffset[Ch];
        if Ch=MDX.MaxChannel then
          MMLSize:=VoiceOffset-MMLOffset[Ch]
          else
          MMLSize:=MMLOffset[Ch+1]-MMLOffset[Ch];
        if MMLSize<=1 then begin // ＭＭＬのサイズが 0byte or 1byte の時はおかしい
          MDXLoadError('Ch.'+IntToStr(Ch+1)+'のSizeが１以下です。');
          exit;
        end;
        with MMLChannel[Ch] do begin
          SetLength(Buffer,MMLSize+8);
          MoveMemory(@Buffer[0],@MDXData[Segment+MMLOffset[Ch]],MMLSize+1);
          Buffer[MMLSize+1]:=$f1; // 安全のため、終了マーカーを付ける。
          Buffer[MMLSize+2]:=$f1;
          Buffer[MMLSize+3]:=$f1;
          Buffer[MMLSize+4]:=$f1;
          Buffer[MMLSize+5]:=$f1;
          Buffer[MMLSize+6]:=$f1;
          Buffer[MMLSize+7]:=$f1;
        end;
      end;
    end;
  end;

  NowDriverVersion:=MXDRVDriverVersion211;
  if ansipos('by moonlight',lowercase(DummyTitle))<>0 then NowDriverVersion:=MXDRVDriverVersion210;

  Result:=True;
end;

const k:Array[0..48] of integer=(
   16,  17,  19,  21,  23,  25,  28,  31,  34,  37,
	 41,  45,  50,  55,  60,  66,  73,  80,  88,  97,
	107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
	279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
	724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552);
// 1707,1878,2066,2272,2500,2750,3025

const estimstep:array[0..15] of shortint=(
	-1, -1, -1, -1, 2, 4, 6, 8,
	-1, -1, -1, -1, 2, 4, 6, 8);

function TMXDRVmDLL.PDXLoad(PDXFilename:string):boolean;
var
  PDXData:array of byte;
  PDXDataPos:integer;
  PDXNo:integer;
  SizeTemp,HeadSize:dword;
  ExistFlag:boolean;
  procedure PDXLoadError(mes:string);
  begin
    InfomationVisible('PDXError.'+mes);
  end;
  procedure LoadPDXData(Filename:string);
  var
    PDXFile:TFileStream;
  begin
    PDXFile:=TFileStream.Create(Filename,fmOpenRead or fmShareDenyNone);
    MDX.PDXFileSize:=PDXFile.Size;
    SetLength(PDXData,MDX.PDXFileSize+1);
    PDXFile.ReadBuffer(PDXData[0],MDX.PDXFileSize);
    PDXFile.Free;
    PDXDataPos:=0;
  end;
  procedure AutoDecordLZX;
  var
    unLZXbuf:array of byte;
    LZXOffset,unLZXSize:integer;
  begin
    LZXOffset:=0;
    unLZXSize:=GetunLZXSize(PDXData,LZXOffset);
    if unLZXSize<>0 then begin
      SetLength(unLZXbuf,unLZXSize+1);
      LZXdecord(PDXData,LZXOffset,unLZXbuf);
      MDX.PDXFileSize:=LZXOffset+unLZXSize;
      SetLength(PDXData,MDX.PDXFileSize+2);
      MoveMemory(@PDXData[LZXOffset],@unLZXbuf[0],unLZXSize+1);
    end;
  end;
  function ReadByte:byte;
  begin
    if PDXDataPos>=MDX.PDXFileSize then begin
      PDXLoadError('PDXReadByte:OverPointer');
      Result:=$00;
      end else begin
      Result:=PDXData[PDXDataPos];
    end;
    inc(PDXDataPos);
  end;
  function ReadDWord:dword;
  begin
    if (PDXDataPos+3)>=MDX.PDXFileSize then begin
      PDXLoadError('PDXReadDWord:OverPointer');
      Result:=$00;
      end else begin
      Result:=(dword(PDXData[PDXDataPos+0]) shl 24)+(dword(PDXData[PDXDataPos+1]) shl 16)+(dword(PDXData[PDXDataPos+2]) shl 8)+dword(PDXData[PDXDataPos+3]);
    end;
    inc(PDXDataPos,4);
  end;
  procedure DecordADPCM(var ADPCM:TADPCM);
  var
    last:integer;
    idx:shortint;
    cnt:integer;
    pos:integer;
    CurADPCM:byte;
    procedure ADPCM2PCM(const curdata:byte);
    var
      dltL:dword;
    begin
      dltL:=(k[idx]*((curdata and 7)*2+1)) shr 3;
      if (curdata and 8)<>0 then dltL:=(dltL xor $ffffffff)+1;
      inc(last,dltL);
      if last<-4095 then last:=-4095;
      if last>4095 then last:=4095;
      ADPCM.PCMData[pos]:=smallint(last shl 3);
      inc(pos);
      inc(idx,estimstep[curdata]);
      if idx<0 then idx:=0;
      if idx>48 then idx:=48;
    end;
  begin
    if ADPCM.PCMData<>nil then begin // MemoryFree
      GlobalFree(HGLOBAL(ADPCM.PCMData));
      ADPCM.PCMData:=nil;
    end;
    if (ADPCM.Enabled=False) or (ADPCM.Size=0) then begin
      exit;
    end;

    ADPCM.PCMData:=Ptr(GlobalAlloc(GMEM_FIXED+GMEM_ZEROINIT,ADPCM.Size*2*2+1));
    pos:=0;
    idx:=0;
    last:=0;
    for cnt:=0 to ADPCM.Size-1 do begin
      CurADPCM:=ADPCM.ADPCMData[cnt];
      ADPCM2PCM(CurADPCM and $0f);
      ADPCM2PCM(CurADPCM shr 4 and $0f);
    end;
  end;
begin
  for PDXNo:=0 to ADPCMCount-1 do begin
    with ADPCM[PDXNo] do begin
      if Enabled=True then begin
        Enabled:=False;
        if ADPCMData<>nil then begin // MemoryFree
          GlobalFree(HGLOBAL(ADPCMData));
          ADPCMData:=nil;
        end;
        if PCMData<>nil then begin // MemoryFree
          GlobalFree(HGLOBAL(PCMData));
          PCMData:=nil;
        end;
      end;
    end;
  end;

  if FileExists(PDXFilename)=False then begin
    PDXLoadError('PDX not found : '+ExtractFilename(PDXFilename));
    Result:=False;
    exit;
  end;

  LoadPDXData(PDXFilename);
  AutoDecordLZX;

  HeadSize:=0;
  PDXNo:=-1;
  repeat
    ExistFlag:=False;
    inc(PDXNo);
    if PDXNo<=(ADPCMCount-1) then begin
      PDXDataPos:=PDXNo*8;
      SizeTemp:=ReadDWord;
      if SizeTemp>dword(MDX.PDXFileSize) then begin
        ExistFlag:=True;
        end else begin
        if HeadSize=0 then begin
          HeadSize:=SizeTemp;
          end else begin
          if (SizeTemp<>0) and (SizeTemp<HeadSize) then HeadSize:=SizeTemp;
        end;
        if HeadSize<>0 then begin
          if ((HeadSize div 8)-1)<=dword(PDXNo) then ExistFlag:=True;
        end;
        if PDXDataPos>=MDX.PDXFileSize then ExistFlag:=True;
      end;
    end;
  until (ExistFlag=True);

  if HeadSize=0 then begin
    PDXLoadError('PDX is Empty : '+ExtractFilename(PDXFilename));
    Result:=False;
    exit;
  end;

  for PDXNo:=0 to (HeadSize div 8)-1 do begin
    with ADPCM[PDXNo] do begin
      PDXDataPos:=PDXNo*8;
      StartAdrs:=ReadDWord;
      Size:=ReadDWord;
      if Size>(2*1024*1024) then begin // Not Supported Beta16bit PCMformat
        Size:=0;
        WriteDebugLog('Not Support Beta16bit PCM : '+ExtractFilename(MDX.PDXFilename));
      end;
      if (StartAdrs+Size)>dword(MDX.PDXFileSize) then begin
        StartAdrs:=0;
        WriteDebugLog('PDX FileError (OverSize) : '+ExtractFilename(MDX.PDXFilename));
      end;
      if StartAdrs>dword(MDX.PDXFileSize) then begin
        StartAdrs:=0;
        WriteDebugLog('PDX FileError (MatchSize) : '+ExtractFilename(MDX.PDXFilename));
      end;
      if (StartAdrs<>0) and (Size<>0) then begin
        if Enabled=True then begin
          WriteDebugLog('PDX FileError (Duplicate) : '+ExtractFilename(MDX.PDXFilename));
          end else begin // ADPCM Read
          Enabled:=True;
          ADPCMData:=Ptr(GlobalAlloc(GMEM_FIXED+GMEM_ZEROINIT,Size+1));
          MoveMemory(@ADPCMData[0],@PDXData[StartAdrs],Size+1);
        end;
      end;
    end;
  end;

  for PDXNo:=0 to ADPCMCount-1 do begin
    if ADPCM[PDXNo].Enabled=True then begin
      DecordADPCM(ADPCM[PDXNo]);
    end;
  end;

  Result:=True;
end;

procedure TMXDRVmDLL.MDXOPMRegisterInit;
var
  Ch:byte;
  PartNo,PartOffset:byte;
begin
  // OPM Register Init.
  for Ch:=0 to 7 do begin
    X68Sound_OPMSet($20+Ch, 0);	// PAN/AF
  end;
  for Ch:=0 to 7 do begin
    X68Sound_OPMSet($08, Ch);
    for PartNo:=0 to 3 do begin
      PartOffset:=Ch+(PartNo*8);
      X68Sound_OPMSet($40+PartOffset, 0); // DT1,MUL
      X68Sound_OPMSet($60+PartOffset, 127); // TL
      X68Sound_OPMSet($80+PartOffset, 0); // KScale,AR
      X68Sound_OPMSet($A0+PartOffset, 31); // AMSEN,D1R
      X68Sound_OPMSet($C0+PartOffset, 31); // DT2,D2R
      X68Sound_OPMSet($E0+PartOffset, 15); // D1L,RR
    end;
  end;
  X68Sound_OPMSet($0f, 0); // Ch.8 NoizeOff
  // MML Struct Init.
  with MDX do begin
    Tempo:=200;
    FadeoutFlag:=False;
    LoopCount:=0;
    MasterVolume:=$ff;
    SLFO3Param:=$1234;
    RunPCM8ppFlag:=False;
    EndFlag:=False;
  end;
  RefTempo;
  X68Sound_TotalVolume(MDX.MasterVolume);
  // MML Channel Parametor Init.
  for Ch:=0 to 15 do begin
    with MMLChannel[Ch] do begin
      Enabled:=True;
      Mute:=False;
      NowPanpot:=3;
      NowPos:=0;
      NowVoice:=0;
      NowVoiceSetting:=-1;
      NowKeycode:=1;
      NowPortament:=0;
      NowSync:=True;
      NowPAMS:=0;
      NowPAMSEnabled:=False;
      ADPCMRate:=4;
      ppEnabled:=False;
      ppFreqCnt:=ppFreq_Var;
      ppFreq:=ppFreqTable[ppFreqCnt];
      ppOffset:=0;
      ppVolume:=0;
      ppVolume16:=16;
      ppPanpot:=0;
      ppConvFunc:=ppConvFunc_NotSupport;
      ppConvPosTable:=nil;
      ppConvModTable:=nil;
      ppData:=nil;
      ppDataSize:=0;

      Slot32Enabled:=False;
      NowCarrierSlot:=0;

      Looped:=False;
      KeyoffMode:=True;
      RestClock:=1;
      StopClock:=1;
      LoopCount[0]:=0;
      LoopMax:=0;

      Noteon:=False;
      VolMode:=False;
      Volume:=8;
      Quartz:=0;
      QuartzMode:=True;
      KeyoffMode:=True;
      Detune:=0;
      Portament:=0;
      KeyonDelay:=0;
      SignalWaitFlag:=True;
      SetSignalWaitFlag:=True;

      SLFODelay:=0;
      SLFONowDelay:=0;

      MPEnabled:=False;
      MPWaveType:=0;
      MPFreq:=0;
      MPDisplace:=0;
      MPMstDisplace:=0;
      MPNowFreq:=0;
      MPNowCount:=0;
      MPNowDetune:=0;

      MAEnabled:=False;
      MAWaveType:=0;
      MAFreq:=0;
      MADisplace:=0;
      MAMstDisplace:=0;
      MANowFreq:=0;
      MANowCount:=0;
      MANowDetune:=0;
    end;
  end;

  if MDX.MaxChannel=8 then begin
    for Ch:=9 to 15 do begin
      with MMLChannel[Ch] do begin
        Enabled:=False;
        Mute:=True;
      end;
    end;
  end;
end;

procedure TMXDRVmDLL.SetOPMVoice_V210(Ch:byte);
var
  PartNo,PartOffset:byte;
  Params:TVoicePartParams;
begin
{$IFDEF UseDebugDriver}
  if Ch>=8 then WriteDebugLog('ChannelError(SetOPMVoice):'+inttostr(Ch));
{$ENDIF}
  SetOPMNoteoff(Ch);

  with OPMVoice[MMLChannel[Ch].NowVoice] do begin
    X68Sound_OPMSet($20+Ch, (MMLChannel[Ch].NowPanpot*64)+(AF and 63));	// PAN/AF
    X68Sound_OPMSet($38+Ch, MMLChannel[Ch].NowPAMS); // PMS/AMS
    MMLChannel[Ch].NowSync:=Sync;
    MMLChannel[Ch].NowCarrierSlot:=CarrierSlot[AF and $7];

    for PartNo:=0 to 3 do begin
      PartOffset:=Ch+PartNo*8;
      Params:=Part[PartNo];
      X68Sound_OPMSet($40+PartOffset, Params[0]); // DT1,MUL
      X68Sound_OPMSet($60+PartOffset, Params[1]); // TL
      X68Sound_OPMSet($80+PartOffset, Params[2]); // KScale,AR
      X68Sound_OPMSet($A0+PartOffset, Params[3]); // AMSEN,D1R
      X68Sound_OPMSet($C0+PartOffset, Params[4]); // DT2,D2R
      X68Sound_OPMSet($E0+PartOffset, Params[5]); // D1L,RR
    end;
  end;
  SetOPMVolume_V210(Ch);
end;

procedure TMXDRVmDLL.SetOPMVoice_V211(Ch:byte);
var
  PartNo,PartOffset:byte;
  Params:TVoicePartParams;
begin
{$IFDEF UseDebugDriver}
  if Ch>=8 then WriteDebugLog('ChannelError(SetOPMVoice):'+inttostr(Ch));
{$ENDIF}
  with MMLChannel[Ch] do begin
    if NowVoiceSetting=NowVoice then exit;
    NowVoiceSetting:=NowVoice;
  end;

  with OPMVoice[MMLChannel[Ch].NowVoice] do begin
//    X68Sound_OPMSet($20+Ch, (MMLChannel[Ch].NowPanpot*64)+(AF and 63));	// PAN/AF
    if Plus17Mode then begin
      MMLChannel[Ch].NowSync:=Sync;
      if Sync=True then begin
        X68Sound_OPMSet($38+Ch, 0); // PMS/AMS
        if MMLChannel[Ch].NowPAMSEnabled=True then begin
          X68Sound_OPMSet($38+Ch, MMLChannel[Ch].NowPAMS); // PMS/AMS
        end;
      end;
    end;
    MMLChannel[Ch].NowCarrierSlot:=CarrierSlot[AF and $7];

    for PartNo:=0 to 3 do begin
      PartOffset:=Ch+PartNo*8;
      Params:=Part[PartNo];
      X68Sound_OPMSet($40+PartOffset, Params[0]); // DT1,MUL
      X68Sound_OPMSet($60+PartOffset, Params[1]); // TL
      X68Sound_OPMSet($80+PartOffset, Params[2]); // KScale,AR
      X68Sound_OPMSet($A0+PartOffset, Params[3]); // AMSEN,D1R
      X68Sound_OPMSet($C0+PartOffset, Params[4]); // DT2,D2R
      X68Sound_OPMSet($E0+PartOffset, Params[5]); // D1L,RR
    end;
  end;
  SetOPMVolume_V211(Ch);
end;

procedure TMXDRVmDLL.SetOPMNoteNumber_V210(Ch:byte;Note:LongInt);
var
  Freq:Longint;
begin
{$IFDEF UseDebugDriver}
  if Ch>=8 then WriteDebugLog('ChannelError(SetOPMNoteNumber):'+inttostr(Ch));
{$ENDIF}

  Note:=Note-3;

  with MMLChannel[Ch] do begin
    Freq:=Detune+(NowPortament div 256)+(MPNowDetune div 256); // 1note / 64pitch
    LastPitch:=(Note*64)+Freq;
  end;

  while Freq<0 do begin
    dec(Note);
    inc(Freq,64);
  end;
  if Freq>=64 then begin
    Note:=Note+(Freq div 64);
    Freq:=Freq mod 64;
  end;

  if (Note<$00) or ($5f<Note) then exit;

  X68Sound_OPMSet($28+Ch,ToneTable[Note]);
  X68Sound_OPMSet($30+Ch,byte(Freq*$4));
end;

procedure TMXDRVmDLL.SetOPMNoteNumber_V211(Ch:byte;Note:LongInt);
var
  Freq:Longint;
begin
{$IFDEF UseDebugDriver}
  if Ch>=8 then WriteDebugLog('ChannelError(SetOPMNoteNumber):'+inttostr(Ch));
{$ENDIF}

  Note:=Note-3;

  with MMLChannel[Ch] do begin
    Freq:=Detune+(NowPortament div 256)+(MPNowDetune div 256); // 1note / 64pitch
    LastPitch:=(Note*64)+Freq;
  end;

  while Freq<0 do begin
    dec(Note);
    inc(Freq,64);
  end;
{
  while Freq>=64 do begin
    inc(Note);
    dec(Freq,64);
  end;
}
{
  if Freq<0 then begin
    Note:=Note-1+(Freq div 64);
    Freq:=Freq mod 64;
  end;
}
  if Freq>=64 then begin
    Note:=Note+(Freq div 64);
    Freq:=Freq mod 64;
  end;

  if (Note<$00) or ($5f<Note) then exit;

  X68Sound_OPMSet($28+Ch,ToneTable[Note]);
  X68Sound_OPMSet($30+Ch,byte(Freq*$4));
end;

procedure TMXDRVmDLL.SetOPMNoteon_V210(Ch:byte;Note:LongInt);
begin
{$IFDEF UseDebugDriver}
  if Ch>=8 then WriteDebugLog('ChannelError(SetOPMNoteon):'+inttostr(Ch));
{$ENDIF}
  if MMLChannel[Ch].Mute=True then exit;

  SetOPMVolume_V210(Ch);
  with OPMVoice[MMLChannel[Ch].NowVoice] do begin
    SetOPMNoteoff(Ch);
    if MMLChannel[Ch].NowSync=True then begin // LFO Sync
      with MMLChannel[Ch] do begin
        MPNowFreq:=1;
        MPNowCount:=0;
        MPNowDetune:=0;
        MPDisplace:=MPMstDisplace;
        MANowFreq:=1;
        MANowCount:=0;
        MANowDetune:=0;
        MADisplace:=MAMstDisplace;
      end;
      X68Sound_OPMSet($01, 2); // LFO Stop
      X68Sound_OPMSet($01, 0); // LFO Start
    end;
    SetOPMNoteNumber_V210(Ch,Note);
    X68Sound_OPMSet($08, (Slot and 15) * 8+Ch); // Slot Open
  end;
end;

procedure TMXDRVmDLL.SetOPMNoteon_V211(Ch:byte;Note:LongInt);
begin
{$IFDEF UseDebugDriver}
  if Ch>=8 then WriteDebugLog('ChannelError(SetOPMNoteon):'+inttostr(Ch));
{$ENDIF}
  if MMLChannel[Ch].Mute=True then exit;

  with OPMVoice[MMLChannel[Ch].NowVoice] do begin
    SetOPMVolume_V211(Ch);
    SetOPMMPInit_V211(ch);
    SetOPMMAInit_V211(ch);
    if MMLChannel[Ch].NowSync=True then begin // LFO Sync
      X68Sound_OPMSet($01, 2); // LFO Stop
      X68Sound_OPMSet($01, 0); // LFO Start
    end;
    SetOPMNoteNumber_V211(Ch,Note);
    X68Sound_OPMSet($08, (Slot and 15) * 8+Ch); // Slot Open
  end;
end;

procedure TMXDRVmDLL.SetOPMNoteoff(Ch:byte);
begin
{$IFDEF UseDebugDriver}
  if Ch>=8 then WriteDebugLog('ChannelError(SetOPMNoteoff):'+inttostr(Ch));
{$ENDIF}

  X68Sound_OPMSet($08, Ch);
end;

procedure TMXDRVmDLL.SetOPMVolume_V210(Ch:byte);
var
  SetVol,Volume:integer;
  TmpCarrierSlot,TmpVoice:Byte;
begin
{$IFDEF UseDebugDriver}
  if Ch>=8 then WriteDebugLog('ChannelError(SetOPMVolume):'+inttostr(Ch));
{$ENDIF}

  if MMLChannel[Ch].Noteon=False then exit;

  with MMLChannel[Ch] do begin
    TmpCarrierSlot:=NowCarrierSlot;
    TmpVoice:=NowVoice;
    SetVol:=($7f-Volume)-(MANowDetune div 256);
  end;

  if SetVol<$00 then SetVol:=$00;
  if $7f<SetVol then SetVol:=$7f;

  if SlottoTL[TmpCarrierSlot,0]=True then begin
    Volume:=OPMVoice[TmpVoice].Part[0][1]+SetVol;
    if Volume>$7f then Volume:=$7f;
    X68Sound_OPMSet($60+Ch+(0*8), Volume); // TL Slot0
  end;
  if SlottoTL[TmpCarrierSlot,1]=True then begin
    Volume:=OPMVoice[TmpVoice].Part[1][1]+SetVol;
    if Volume>$7f then Volume:=$7f;
    X68Sound_OPMSet($60+Ch+(1*8), Volume); // TL Slot1
  end;
  if SlottoTL[TmpCarrierSlot,2]=True then begin
    Volume:=OPMVoice[TmpVoice].Part[2][1]+SetVol;
    if Volume>$7f then Volume:=$7f;
    X68Sound_OPMSet($60+Ch+(2*8), Volume); // TL Slot2
  end;
  if SlottoTL[TmpCarrierSlot,3]=True then begin
    Volume:=OPMVoice[TmpVoice].Part[3][1]+SetVol;
    if Volume>$7f then Volume:=$7f;
    X68Sound_OPMSet($60+Ch+(3*8), Volume); // TL Slot3
  end;
end;

procedure TMXDRVmDLL.SetOPMVolume_V211(Ch:byte);
var
  SetVol,Volume:integer;
  TmpCarrierSlot,TmpVoice:Byte;
begin
{$IFDEF UseDebugDriver}
  if Ch>=8 then WriteDebugLog('ChannelError(SetOPMVolume):'+inttostr(Ch));
{$ENDIF}

  if MMLChannel[Ch].Noteon=False then exit;

  with MMLChannel[Ch] do begin
    TmpCarrierSlot:=NowCarrierSlot;
    TmpVoice:=NowVoice;
    if VolMode=False then
      SetVol:=OPMVolTbl[Volume]
      else
      SetVol:=Volume;
    SetVol:=$7f-(SetVol+(MANowDetune div 256));
  end;

  if SetVol<$00 then SetVol:=$00;
  if $7f<SetVol then SetVol:=$7f;

  if SlottoTL[TmpCarrierSlot,0]=True then begin
    Volume:=OPMVoice[TmpVoice].Part[0][1]+SetVol;
    if Volume>$7f then Volume:=$7f;
    X68Sound_OPMSet($60+Ch+(0*8), Volume); // TL Slot0
  end;
  if SlottoTL[TmpCarrierSlot,1]=True then begin
    Volume:=OPMVoice[TmpVoice].Part[1][1]+SetVol;
    if Volume>$7f then Volume:=$7f;
    X68Sound_OPMSet($60+Ch+(1*8), Volume); // TL Slot1
  end;
  if SlottoTL[TmpCarrierSlot,2]=True then begin
    Volume:=OPMVoice[TmpVoice].Part[2][1]+SetVol;
    if Volume>$7f then Volume:=$7f;
    X68Sound_OPMSet($60+Ch+(2*8), Volume); // TL Slot2
  end;
  if SlottoTL[TmpCarrierSlot,3]=True then begin
    Volume:=OPMVoice[TmpVoice].Part[3][1]+SetVol;
    if Volume>$7f then Volume:=$7f;
    X68Sound_OPMSet($60+Ch+(3*8), Volume); // TL Slot3
  end;
end;

procedure TMXDRVmDLL.SetADPCMMode_V210(Ch:byte;EnabledNoteon:boolean);
var
  SetVol:LongInt;
  SetMode:dword;
  ADPCMNo:word;
begin
{$IFDEF UseDebugDriver}
  if Ch<=7 then WriteDebugLog('ChannelError(SetADPCMMode):'+inttostr(Ch));
{$ENDIF}

  if MMLChannel[Ch].Noteon=False then exit;

  with MMLChannel[Ch] do begin
    LastPitch:=(NowKeycode-1)*64;

    if Mute=True then Noteon:=False;
    if NowKeycode=0 then exit;

    if MDX.ExtendPCM8=True then
      SetVol:=Volume
      else
      SetVol:=$40;

    if SetVol<$00 then SetVol:=$00;
    if $7f<SetVol then SetVol:=$7f;

{
    if SetVol=$00 then begin
      SetADPCMNoteoff(Ch);
      end else begin
      SetMode:=(SetVol div 8)*$10000+(ADPCMRate*$100)+NowPanpot;
      if (Noteon=True) and (EnabledNoteon=True) then begin
        ADPCMNo:=NowVoice*$60+(NowKeycode-1);
        if ADPCM[ADPCMNo].ADPCMData<>nil then
          X68Sound_Pcm8_Out(Ch-8,addr(ADPCM[ADPCMNo].ADPCMData[0]),SetMode,ADPCM[ADPCMNo].Size);
        end else begin
        X68Sound_Pcm8_SetMode(Ch-8,SetMode);
      end;
    end;
}
  end;

  SetVol:=SetVol div 8;

  if MMLChannel[Ch].ADPCMRate>=$07 then begin
    with MMLChannel[Ch] do begin
      ppVolume:=SetVol;
      ppVolume16:=ppVolumeTable[ppVolume];
      ppPanpot:=NowPanpot;
      ppKeycode:=NowVoice*$60+(NowKeycode-1);
      ppData:=ADPCM[ppKeycode].ADPCMData;
      ppDataSize:=ADPCM[ppKeycode].Size;
      case ADPCMRate of
{
        $00: ppFreqCnt:=3906; // under ADPCM
        $01: ppFreqCnt:=5208;
        $02: ppFreqCnt:=7812;
        $03: ppFreqCnt:=10416;
        $04: ppFreqCnt:=15625;
        $05: ppFreqCnt:=15625; // 16bitSignedPCM
        $06: ppFreqCnt:=15625; // 8bitSignedPCM
}
        $07: ppFreqCnt:=ppFreq_44100; // 16bitSignedPCM
        $08: ppFreqCnt:=ppFreq_15625; // under 16bitSignedPCM
        $09: ppFreqCnt:=ppFreq_16000;
        $0a: ppFreqCnt:=ppFreq_22050;
        $0b: ppFreqCnt:=ppFreq_24000;
        $0c: ppFreqCnt:=ppFreq_32000;
        $0d: ppFreqCnt:=ppFreq_44100;
        $0e: ppFreqCnt:=ppFreq_48000;
        $0f: ppFreqCnt:=ppFreq_44100; // VariabledFreq notSupport
        $10: ppFreqCnt:=ppFreq_15625; // under 8bitSignedPCM
        $11: ppFreqCnt:=ppFreq_16000;
        $12: ppFreqCnt:=ppFreq_22050;
        $13: ppFreqCnt:=ppFreq_24000;
        $14: ppFreqCnt:=ppFreq_32000;
        $15: ppFreqCnt:=ppFreq_44100;
        $16: ppFreqCnt:=ppFreq_48000;
        $17: ppFreqCnt:=ppFreq_44100; // VariabledFreq notSupport
        $18: ppFreqCnt:=ppFreq_15625; // under 16bitSignedPCM
        $19: ppFreqCnt:=ppFreq_16000;
        $1a: ppFreqCnt:=ppFreq_22050;
        $1b: ppFreqCnt:=ppFreq_24000;
        $1c: ppFreqCnt:=ppFreq_32000;
        $1d: ppFreqCnt:=ppFreq_44100;
        $1e: ppFreqCnt:=ppFreq_48000;
        $1f: ppFreqCnt:=ppFreq_44100; // VariabledFreq notSupport
        $20: ppFreqCnt:=ppFreq_15625; // under 8bitSignedPCM Stereo
        $21: ppFreqCnt:=ppFreq_16000;
        $22: ppFreqCnt:=ppFreq_22050;
        $23: ppFreqCnt:=ppFreq_24000;
        $24: ppFreqCnt:=ppFreq_32000;
        $25: ppFreqCnt:=ppFreq_44100;
        $26: ppFreqCnt:=ppFreq_48000;
        $27: ppFreqCnt:=ppFreq_44100; // VariabledFreq notSupport
        $28: ppFreqCnt:=ppFreq_44100; // Valiabled ADPCM Monoural notSupport
        $29: ppFreqCnt:=ppFreq_44100; // Valiabled 16bit Signed PCM Monoural
//      $2a-$7f: // Reserved.
      end;

      ppFreq:=ppFreqTable[ppFreqCnt];
      ppConvPosTable:=ppConvPosTables[ppFreqCnt];
      ppConvModTable:=ppConvModTables[ppFreqCnt];

      ppConvFunc:=ppConvFunc_NotSupport;
      if ADPCMRate=$07 then ppConvFunc:=ppConvFunc_Mono16bit;
      if ($08<=ADPCMRate) and (ADPCMRate<=$0f) then ppConvFunc:=ppConvFunc_Mono16bit;
      if ($10<=ADPCMRate) and (ADPCMRate<=$17) then ppConvFunc:=ppConvFunc_Mono8bit;
      if ($18<=ADPCMRate) and (ADPCMRate<=$1f) then ppConvFunc:=ppConvFunc_Stereo16bit;
      if ($20<=ADPCMRate) and (ADPCMRate<=$27) then ppConvFunc:=ppConvFunc_Stereo8bit;
      if ADPCMRate=$28 then ppConvFunc:=ppConvFunc_NotSupport;
      if ADPCMRate=$29 then ppConvFunc:=ppConvFunc_Mono16bit;

      if (Noteon=True) and (EnabledNoteon=True) then begin
        if ppData<>nil then begin
          ppEnabled:=True;
          ppOffset:=0;
          CheckppAllChannel;
        end;
        end else begin
      end;
    end;
    end else begin
    if ADPCMSRCMode=ADPCMSRCMode_X68Sound then begin
      with MMLChannel[Ch] do begin
        SetMode:=SetVol*$10000+(ADPCMRate*$100)+NowPanpot;
        if (Noteon=True) and (EnabledNoteon=True) then begin
          ADPCMNo:=NowVoice*$60+(NowKeycode-1);
          if ADPCM[ADPCMNo].ADPCMData<>nil then
            X68Sound_Pcm8_Out(Ch-8,addr(ADPCM[ADPCMNo].ADPCMData[0]),SetMode,ADPCM[ADPCMNo].Size);
          end else begin
          X68Sound_Pcm8_SetMode(Ch-8,SetMode);
        end;
      end;
      end else begin
      with MMLChannel[Ch] do begin
        ppVolume:=SetVol;
        ppVolume16:=ppVolumeTable[ppVolume];
        ppPanpot:=NowPanpot;
        ppKeycode:=NowVoice*$60+(NowKeycode-1);
        ppData:=ADPCM[ppKeycode].ADPCMData;
        ppDataSize:=ADPCM[ppKeycode].Size;
        case ADPCMRate of
          $00: ppFreqCnt:=ppFreq_3906; // under ADPCM
          $01: ppFreqCnt:=ppFreq_5208;
          $02: ppFreqCnt:=ppFreq_7812;
          $03: ppFreqCnt:=ppFreq_10416;
          $04: ppFreqCnt:=ppFreq_15625;
          $05: ppFreqCnt:=ppFreq_15625; // 16bitSignedPCM
          $06: ppFreqCnt:=ppFreq_15625; // 8bitSignedPCM
        end;

        ppFreq:=ppFreqTable[ppFreqCnt];
        ppConvPosTable:=ppConvPosTables[ppFreqCnt];
        ppConvModTable:=ppConvModTables[ppFreqCnt];

        if ADPCMRate<=$04 then begin
          ppConvFunc:=ppConvFunc_ADPCM;
          end else begin
          if ADPCMRate=$05 then ppConvFunc:=ppConvFunc_Mono16bit;
          if ADPCMRate=$06 then ppConvFunc:=ppConvFunc_Mono8bit;
        end;

        if (Noteon=True) and (EnabledNoteon=True) then begin
          if (ppData<>nil) and (ADPCM[ppKeycode].Size<>0) then begin
            ppEnabled:=True;
            ppOffset:=0;
            CheckppAllChannel;
          end;
          end else begin
        end;
      end;
    end;
  end;
end;

procedure TMXDRVmDLL.SetADPCMMode_V211(Ch:byte;EnabledNoteon:boolean);
var
  SetVol:LongInt;
  SetMode:dword;
  ADPCMNo:word;
begin
{$IFDEF UseDebugDriver}
  if Ch<=7 then WriteDebugLog('ChannelError(SetADPCMMode):'+inttostr(Ch));
{$ENDIF}

  if MMLChannel[Ch].Noteon=False then exit;

  with MMLChannel[Ch] do begin
    LastPitch:=(NowKeycode-1)*64;

    if Mute=True then Noteon:=False;
    if NowKeycode=0 then exit;

    if MDX.ExtendPCM8=True then begin
      if VolMode=False then
        SetVol:=Volume
        else
        SetVol:=PCMVolTbl[$7f-Volume];
      end else begin
      SetVol:=$08;
    end;

    if SetVol<$0 then SetVol:=$0;
    if $f<SetVol then SetVol:=$f;
  end;

  if MMLChannel[Ch].ADPCMRate>=$07 then begin
    with MMLChannel[Ch] do begin
      ppVolume:=SetVol;
      ppVolume16:=ppVolumeTable[ppVolume];
      ppPanpot:=NowPanpot;
      ppKeycode:=NowVoice*$60+(NowKeycode-1);
      ppData:=ADPCM[ppKeycode].ADPCMData;
      ppDataSize:=ADPCM[ppKeycode].Size;
      case ADPCMRate of
{
        $00: ppFreqCnt:=3906; // under ADPCM
        $01: ppFreqCnt:=5208;
        $02: ppFreqCnt:=7812;
        $03: ppFreqCnt:=10416;
        $04: ppFreqCnt:=15625;
        $05: ppFreqCnt:=15625; // 16bitSignedPCM
        $06: ppFreqCnt:=15625; // 8bitSignedPCM
}
        $07: ppFreqCnt:=ppFreq_44100; // 16bitSignedPCM
        $08: ppFreqCnt:=ppFreq_15625; // under 16bitSignedPCM
        $09: ppFreqCnt:=ppFreq_16000;
        $0a: ppFreqCnt:=ppFreq_22050;
        $0b: ppFreqCnt:=ppFreq_24000;
        $0c: ppFreqCnt:=ppFreq_32000;
        $0d: ppFreqCnt:=ppFreq_44100;
        $0e: ppFreqCnt:=ppFreq_48000;
        $0f: ppFreqCnt:=ppFreq_44100; // VariabledFreq notSupport
        $10: ppFreqCnt:=ppFreq_15625; // under 8bitSignedPCM
        $11: ppFreqCnt:=ppFreq_16000;
        $12: ppFreqCnt:=ppFreq_22050;
        $13: ppFreqCnt:=ppFreq_24000;
        $14: ppFreqCnt:=ppFreq_32000;
        $15: ppFreqCnt:=ppFreq_44100;
        $16: ppFreqCnt:=ppFreq_48000;
        $17: ppFreqCnt:=ppFreq_44100; // VariabledFreq notSupport
        $18: ppFreqCnt:=ppFreq_15625; // under 16bitSignedPCM
        $19: ppFreqCnt:=ppFreq_16000;
        $1a: ppFreqCnt:=ppFreq_22050;
        $1b: ppFreqCnt:=ppFreq_24000;
        $1c: ppFreqCnt:=ppFreq_32000;
        $1d: ppFreqCnt:=ppFreq_44100;
        $1e: ppFreqCnt:=ppFreq_48000;
        $1f: ppFreqCnt:=ppFreq_44100; // VariabledFreq notSupport
        $20: ppFreqCnt:=ppFreq_15625; // under 8bitSignedPCM Stereo
        $21: ppFreqCnt:=ppFreq_16000;
        $22: ppFreqCnt:=ppFreq_22050;
        $23: ppFreqCnt:=ppFreq_24000;
        $24: ppFreqCnt:=ppFreq_32000;
        $25: ppFreqCnt:=ppFreq_44100;
        $26: ppFreqCnt:=ppFreq_48000;
        $27: ppFreqCnt:=ppFreq_44100; // VariabledFreq notSupport
        $28: ppFreqCnt:=ppFreq_44100; // Valiabled ADPCM Monoural notSupport
        $29: ppFreqCnt:=ppFreq_44100; // Valiabled 16bit Signed PCM Monoural
//      $2a-$7f: // Reserved.
      end;

      ppFreq:=ppFreqTable[ppFreqCnt];
      ppConvPosTable:=ppConvPosTables[ppFreqCnt];
      ppConvModTable:=ppConvModTables[ppFreqCnt];

      ppConvFunc:=ppConvFunc_NotSupport;
      if ADPCMRate=$07 then ppConvFunc:=ppConvFunc_Mono16bit;
      if ($08<=ADPCMRate) and (ADPCMRate<=$0f) then ppConvFunc:=ppConvFunc_Mono16bit;
      if ($10<=ADPCMRate) and (ADPCMRate<=$17) then ppConvFunc:=ppConvFunc_Mono8bit;
      if ($18<=ADPCMRate) and (ADPCMRate<=$1f) then ppConvFunc:=ppConvFunc_Stereo16bit;
      if ($20<=ADPCMRate) and (ADPCMRate<=$27) then ppConvFunc:=ppConvFunc_Stereo8bit;
      if ADPCMRate=$28 then ppConvFunc:=ppConvFunc_NotSupport;
      if ADPCMRate=$29 then ppConvFunc:=ppConvFunc_Mono16bit;

      if (Noteon=True) and (EnabledNoteon=True) then begin
        if ppData<>nil then begin
          ppEnabled:=True;
          ppOffset:=0;
          CheckppAllChannel;
        end;
        end else begin
      end;
    end;
    end else begin
    if ADPCMSRCMode=ADPCMSRCMode_X68Sound then begin
      with MMLChannel[Ch] do begin
        SetMode:=SetVol*$10000+(ADPCMRate*$100)+NowPanpot;
        if (Noteon=True) and (EnabledNoteon=True) then begin
          ADPCMNo:=NowVoice*$60+(NowKeycode-1);
          if ADPCM[ADPCMNo].ADPCMData<>nil then
            X68Sound_Pcm8_Out(Ch-8,addr(ADPCM[ADPCMNo].ADPCMData[0]),SetMode,ADPCM[ADPCMNo].Size);
          end else begin
          X68Sound_Pcm8_SetMode(Ch-8,SetMode);
        end;
      end;
      end else begin
      with MMLChannel[Ch] do begin
        ppVolume:=SetVol;
        ppVolume16:=ppVolumeTable[ppVolume];
        ppPanpot:=NowPanpot;
        ppKeycode:=NowVoice*$60+(NowKeycode-1);
        ppData:=ADPCM[ppKeycode].ADPCMData;
        ppDataSize:=ADPCM[ppKeycode].Size;
        case ADPCMRate of
          $00: ppFreqCnt:=ppFreq_3906; // under ADPCM
          $01: ppFreqCnt:=ppFreq_5208;
          $02: ppFreqCnt:=ppFreq_7812;
          $03: ppFreqCnt:=ppFreq_10416;
          $04: ppFreqCnt:=ppFreq_15625;
          $05: ppFreqCnt:=ppFreq_15625; // 16bitSignedPCM
          $06: ppFreqCnt:=ppFreq_15625; // 8bitSignedPCM
        end;

        ppFreq:=ppFreqTable[ppFreqCnt];
        ppConvPosTable:=ppConvPosTables[ppFreqCnt];
        ppConvModTable:=ppConvModTables[ppFreqCnt];

        if ADPCMRate<=$04 then begin
          ppConvFunc:=ppConvFunc_ADPCM;
          end else begin
          if ADPCMRate=$05 then ppConvFunc:=ppConvFunc_Mono16bit;
          if ADPCMRate=$06 then ppConvFunc:=ppConvFunc_Mono8bit;
        end;

        if (Noteon=True) and (EnabledNoteon=True) then begin
          if (ppData<>nil) and (ADPCM[ppKeycode].Size<>0) then begin
            ppEnabled:=True;
            ppOffset:=0;
            CheckppAllChannel;
          end;
          end else begin
        end;
      end;
    end;
  end;
end;

procedure TMXDRVmDLL.SetADPCMNoteoff(Ch:byte);
begin
{$IFDEF UseDebugDriver}
  if Ch<=7 then WriteDebugLog('ChannelError(SetADPCMNoteoff):'+inttostr(Ch));
{$ENDIF}

  MMLChannel[Ch].LastPitch:=0;
  MMLChannel[Ch].ppEnabled:=False;
  CheckppAllChannel;
  X68Sound_Pcm8_Out(Ch-8,nil,$ffff,0);
end;

procedure TMXDRVmDLL.SetOPMMPInit_V211(Ch:byte);
begin
{$IFDEF UseDebugDriver}
  if Ch>=8 then WriteDebugLog('ChannelError(MPInit):'+inttostr(Ch));
{$ENDIF}

  with MMLChannel[ch] do begin
    MPNowFreq:=1;
    if MPWaveType=2 then MPNowFreq:=MPFreq div 2;
    MPNowCount:=0;
    MPNowDetune:=0;
    MPDisplace:=MPMstDisplace;
    if MPEnabled=False then MPNowDetune:=0;
  end;
end;

procedure TMXDRVmDLL.SetOPMMAInit_V211(Ch:byte);
begin
{$IFDEF UseDebugDriver}
  if Ch>=8 then WriteDebugLog('ChannelError(MPInit):'+inttostr(Ch));
{$ENDIF}

  with MMLChannel[ch] do begin
    MANowFreq:=1;
    MANowCount:=0;
    MANowDetune:=0;
    MADisplace:=MAMstDisplace;
    if (MADisplace<0) and (MAWaveType=2) then MANowDetune:=MADisplace*MAFreq;
    if MAEnabled=False then MANowDetune:=0;
  end;
end;

procedure TMXDRVmDLL.MMLCompile_V210;
var
  Ch,ChCnt:byte;
begin
  ChCnt:=MDX.MaxChannel;
  for Ch:=0 to ChCnt do begin
    with MMLChannel[Ch] do begin
      if (Enabled=True) and (SignalWaitFlag=True) then begin
        if NowKeycode<>0 then begin
          if Portament<>0 then begin
            inc(NowPortament,Portament);
            if Ch<=7 then SetOPMNoteNumber_V210(Ch,NowKeycode);
          end;
          if (KeyoffMode=True) and (StopClock>=1) then begin
            dec(StopClock);
            if StopClock=0 then begin
              Portament:=0;
              NowPortament:=0;
              NowKeycode:=0;
              StopClock:=0;
              if Ch<=7 then
                SetOPMNoteoff(Ch)
                else
                SetADPCMNoteoff(Ch);
            end;
          end;
        end;
        if RestClock>=1 then begin
          dec(RestClock);
          if RestClock=0 then MMLAnalize_V210(Ch,True);
        end;
      end;
    end;
  end;

  ProcessSLFO_V210;
  ProcessFadeout;
end;

procedure TMXDRVmDLL.MMLCompile_V211;
var
  Ch,ChCnt:byte;
  Processed:array[0..15] of boolean;
  Processing:boolean;
  LoopLimit:integer;
  procedure Process(Ch:integer);
  begin
    with MMLChannel[Ch] do begin
      if NowKeycode<>0 then begin
        if Portament<>0 then begin
          inc(NowPortament,Portament);
          if Ch<=7 then SetOPMNoteNumber_V211(Ch,NowKeycode);
        end;
        if (KeyoffMode=True) and (StopClock>=1) then begin
          dec(StopClock);
          if StopClock=0 then begin
            Portament:=0;
            NowPortament:=0;
            NowKeycode:=0;
            StopClock:=0;
            if Ch<=7 then
              SetOPMNoteoff(Ch)
              else
              SetADPCMNoteoff(Ch);
          end;
        end;
      end;
      if RestClock>=1 then begin
        dec(RestClock);
      end;
      if RestClock<=0 then MMLAnalize_V211(Ch,True);
    end;
  end;
begin
  ChCnt:=MDX.MaxChannel;

  for Ch:=0 to ChCnt do begin
    Processed[Ch]:=False;
    with MMLChannel[Ch] do begin
      SetSignalWaitFlag:=False;
    end;
  end;

  Processing:=True;
  LoopLimit:=$ff;

  while (Processing=True) do begin
    dec(LoopLimit);
    if LoopLimit=$00 then begin
      WriteDebugLog('同期コマンドで無限ループに入りました。強制中断されます。');
      for Ch:=0 to ChCnt do begin
        MMLChannel[Ch].Enabled:=False;
      end;
      exit;
    end;

    Processing:=False;
    for Ch:=0 to ChCnt do begin
      with MMLChannel[Ch] do begin
        if (Processed[Ch]=False) and (Enabled=True) and (SignalWaitFlag=True) then begin
          Process(Ch);
          Processing:=True;
          Processed[Ch]:=True;
          if SignalWaitFlag=False then Processed[Ch]:=False;
        end;
      end;
    end;
    for Ch:=0 to ChCnt do begin
      with MMLChannel[Ch] do begin
        if (SignalWaitFlag=False) and (SetSignalWaitFlag=True) then begin
          Processing:=True;
          Processed[Ch]:=False;
          SignalWaitFlag:=True;
        end;
      end;
    end;
  end;

  ProcessSLFO_V211;
  ProcessFadeout;
end;

procedure TMXDRVmDLL.ProcessSLFO_V210;
var
  Ch:byte;
begin
  for Ch:=0 to 7 do begin // Phase,AMP SoftLFO OPMonly
    with MMLChannel[Ch] do begin
      if Enabled=True then begin // Phase
        if SLFONowDelay<>0 then begin
          dec(SLFONowDelay);
          end else begin
          if MPEnabled=True then begin
            inc(MPNowFreq);
            if MPNowFreq>=MPFreq then begin // 周期ループアウト
              dec(MPNowFreq,MPFreq);
              inc(MPNowCount);
              case MPWaveType of
                0: begin // 鋸波
                  if MPNowCount=1 then MPNowCount:=0;
                  MPNowDetune:=-MPDisplace div 2;
                end;
                1: begin // 矩形波
                  case MPNowCount of
                    0: MPNowDetune:=-MPDisplace;
                    1: MPNowDetune:=+MPDisplace;
                    2: MPNowCount:=0;
                  end;
                end;
                2: begin // 三角波
                  if MPNowCount=4 then MPNowCount:=0;
                end;
              end;
              end else begin // 周期内
              case MPWaveType of
                0: begin
                  inc(MPNowDetune,MPDisplace);
                end;
                2: begin
                  case MPNowCount of
                    0: inc(MPNowDetune,MPDisplace);
                    1: dec(MPNowDetune,MPDisplace);
                    2: dec(MPNowDetune,MPDisplace);
                    3: inc(MPNowDetune,MPDisplace);
                  end;
                end;
              end;
              SetOPMNoteNumber_V210(Ch,NowKeycode);
            end;
          end;
          if MAEnabled=True then begin // AMP
            inc(MANowFreq);
            if MANowFreq>=MAFreq then begin // 周期ループアウト
              dec(MANowFreq,MAFreq);
              inc(MANowCount);
              case MAWaveType of
                0: begin // 鋸波
                  if MANowCount=1 then MANowCount:=0;
                  MANowDetune:=0;
                end;
                1: begin // 矩形波
                  case MANowCount of
                    0: MANowDetune:=-MADisplace;
                    1: MANowDetune:=0;
                    2: MANowCount:=0;
                  end;
                end;
                2: begin // 三角波
                  if MANowCount=4 then MANowCount:=0;
                end;
              end;
              end else begin // 周期内
              case MAWaveType of
                0: begin
                  MANowDetune:=MANowDetune-MADisplace;
                end;
                2: begin
                  case MANowCount of
                    0: dec(MANowDetune,MADisplace);
                    1: dec(MANowDetune,MADisplace);
                    2: inc(MANowDetune,MADisplace);
                    3: inc(MANowDetune,MADisplace);
                  end;
                end;
              end;
              SetOPMVolume_V210(Ch);
            end;
          end;
        end;
      end;
    end;
  end;
end;

procedure TMXDRVmDLL.ProcessSLFO_V211;
var
  Ch:byte;
  tmp64:Int64; // 逆櫛形？用テンポラリ
begin
  // SoftLFOはL001050から呼ばれる

  // -----------------------------------------------

  // SoftPhaseLFO
  // UBYTE volatile *S0026;  // Pitch LFO Type
  // ULONG S002a;  // Pitch LFO offset start
  // ULONG S002e;  // Pitch LFO delta start
  // ULONG S0032;  // Pitch LFO delta 変移量
  // ULONG S0036;  // Pitch LFO offset 最終加算音程
  // UWORD S003a;  // Pitch LFO length (cooked)
  // UWORD S003c;  // Pitch LFO length 長さ
  // UWORD S003e;  // Pitch LFO length counter 現在位置

  // code.L0010b4
  // A0=S0026 Pitch LFO Type
  // D1=S0032 Pitch LFO delta
  // A0:0:L00095a 何もしない
  // A0:1:L0010be 鋸波
  // A0:2:L0010d4 矩形波
  // A0:3:L0010ea 三角波
  // A0:4:L001100 不明
  
  // code.L0010be 鋸波
  // D1=S0032 Pitch LFO delta
  // ULONG S0036;  // Pitch LFO offset 最終加算音程
  // UWORD S003c;  // Pitch LFO length 長さ
  // UWORD S003e;  // Pitch LFO length counter 現在位置
  //
  // for C
  // A6->S0036 += D1;
  // A6->S003e--;
  // if ( A6->S003e ) goto L0010d2;
  // A6->S003e = A6->S003c;
  // A6->S0036 = -A6->S0036;
  //
  // for Delphi
  // with A6 do begin
  //   inc(S0036,D1);
  //   dec(S003e);
  //   if S003e=0 then begin
  //     S003e:=S003c;
  //     S0036:=-S0036;
  //   end;
  // end;

  // code.L0010d4 矩形波
  // D1=S0032 Pitch LFO delta
  // ULONG S0032;  // Pitch LFO delta 変移量
  // ULONG S0036;  // Pitch LFO offset 最終加算音程
  // UWORD S003c;  // Pitch LFO length 長さ
  // UWORD S003e;  // Pitch LFO length counter 現在位置
  //
  // for C
  // A6->S0036 = D1;
  // A6->S003e--;
  // if ( A6->S003e ) goto L0010e8;
  // A6->S003e = A6->S003c;
  // A6->S0032 = -A6->S0032;
  //
  // for Delphi
  // with A6 do begin
  //   S0036:=D1;
  //   dec(S003e);
  //   if S003e=0 then begin
  //     S003e:=S003c;
  //     S0032:=-S0032;
  //   end;
  // end;

  // code.L0010ea 三角波
  // D1=S0032 Pitch LFO delta
  // ULONG S0032;  // Pitch LFO delta 変移量
  // ULONG S0036;  // Pitch LFO offset 最終加算音程
  // UWORD S003c;  // Pitch LFO length 長さ
  // UWORD S003e;  // Pitch LFO length counter 現在位置
  //
  // for C
  // A6->S0036 += D1;
  // A6->S003e--;
  // if ( A6->S003e ) goto L0010fe;
  // A6->S003e = A6->S003c;
  // A6->S0032 = -A6->S0032;
  //
  // for Delphi
  // with A6 do begin
  //   inc(S0036,D1);
  //   dec(S003e);
  //   if S003e=0 then begin
  //     S003e:=S003c;
  //     S0032:=-S0032;
  //   end;
  // end;

  // A0:4:L001100 ランダム波
  // D1=S0032 Pitch LFO delta
  // ULONG S0036;  // Pitch LFO offset 最終加算音程
  // UWORD S003c;  // Pitch LFO length 長さ
  // UWORD S003e;  // Pitch LFO length counter 現在位置
  //
  // for C
  // S003e--;
  // if ( S003e ) goto L001114;
  // L00117a();
  // D0 = (SWORD)D0 * (SWORD)D1;
  // S0036 = D0;
  // S003e = S003c;
  //
  // for Delphi
  // with A6 do begin
  //   dec(S003e);
  //   if S003e=0 then begin
  //     S003e:=S003c;
  //     L00117a();
  //     S0036:=D0*D1;
  //   end;
  // end;

  // -----------------------------------------------

  // SoftAmpLFO
  // UBYTE volatile *S0040;  // Volume LFO Type
  // UWORD S0044;  // Volume LFO delta start
  // UWORD S0046;  // Volume LFO delta (cooked)
  // UWORD S0048;  // Volume LFO delta 変移量
  // UWORD S004a;  // Volume LFO offset 最終加算音程
  // UWORD S004c;  // Volume LFO length 長さ
  // UWORD S004e;  // Volume LFO length counter 現在位置

  // code.L001116
  // A0=S0040 Volume LFO Type
  // D1=S0048 Volume LFO delta
  // A0:0:L00095a 何もしない
  // A0:1:L001120 鋸波
  // A0:2:L001138 矩形波
  // A0:3:L00114e 三角波
  // A0:4:L001164 不明

  // code.L001120 鋸波
  // D1=S0048 Volume LFO delta
  // UWORD S0046;  // Volume LFO delta (cooked)
  // UWORD S004a;  // Volume LFO offset 最終加算音程
  // UWORD S004c;  // Volume LFO length 長さ
  // UWORD S004e;  // Volume LFO length counter 現在位置
  //
  // for C
  // A6->S004a += D1;
  // A6->S004e--;
  // if ( A6->S004e ) goto L001136;
  // A6->S004e = A6->S004c;
  // A6->S004a = A6->S0046;
  //
  // for Delphi
  // with A6 do begin
  //   inc(S004a,D1);
  //   dec(S004e);
  //   if S004e=0 then begin
  //     S004e:=S004c;
  //     S004a:=S0046;
  //   end;
  // end;

  // code.L001138 矩形波
  // D1=S0048 Volume LFO delta
  // UWORD S0048;  // Volume LFO delta 変移量
  // UWORD S004a;  // Volume LFO offset 最終加算音程
  // UWORD S004c;  // Volume LFO length 長さ
  // UWORD S004e;  // Volume LFO length counter 現在位置
  //
  // for C
  // A6->S004e--;
  // if ( A6->S004e ) goto L00114c;
  // A6->S004e = A6->S004c;
  // A6->S004a += D1;
  // A6->S0048 = -A6->S0048;
  //
  // for Delphi
  // with A6 do begin
  //   dec(S004e);
  //   if S004e=0 then begin
  //     S004e:=S004c;
  //     inc(S004a,D1);
  //     S0048:=-S0048;
  //   end;
  // end;

  // code.L00114e 三角波
  // D1=S0048 Volume LFO delta
  // UWORD S0048;  // Volume LFO delta 変移量
  // UWORD S004a;  // Volume LFO offset 最終加算音程
  // UWORD S004c;  // Volume LFO length 長さ
  // UWORD S004e;  // Volume LFO length counter 現在位置
  //
  // for C
  // A6->S004a += D1;
  // A6->S004e--;
  // if ( A6->S004e ) goto L001162;
  // A6->S004e = A6->S004c;
  // A6->S0048 = -A6->S0048;
  //
  // for Delphi
  // with A6 do begin
  //   inc(S004a,D1);
  //   dec(S004e);
  //   if S004e=0 then begin
  //     S004e:=S004c;
  //     S0048:=-S0048;
  //   end;
  // end;

  // A0:4:L001100 ランダム波
  // D1=S0048 Volume LFO delta
  // UWORD S0048;  // Volume LFO delta 変移量
  // UWORD S004a;  // Volume LFO offset 最終加算音程
  // UWORD S004c;  // Volume LFO length 長さ
  // UWORD S004e;  // Volume LFO length counter 現在位置
  //
  // for C
  // A6->S004e--;
  // if ( A6->S004e ) goto L001178;
  // L00117a();
  // D1 = (SWORD)D1 * (SWORD)D0;
  // A6->S004e = A6->S004c;
  // A6->S004a = D1;
  //
  // for Delphi
  // with A6 do begin
  //   dec(S004e);
  //   if S004e=0 then begin
  //     S004e:=S004c;
  //     L00117a();
  //     S004a:=D0*D1;
  //   end;
  // end;

  // L00117a 不明(L001100,L001164)から呼ばれるサブルーチン
  // var L001190:word=$1234;
  //
  // for C
  // D0 = L001190;
  // D0 *= 0xc549;
  // D0 += 0x0c;
  // L001190 = D0;
  // D0 >>= 8;
  //
  // for Delphi
  // L001190:=(L001190*$c549)+0x0c;
  // D0:=L001190 shr 8;

  MDX.SLFO3Param:=SmallInt(LongInt(MDX.SLFO3Param*$c549)+$0c);

  for Ch:=0 to 7 do begin // Phase,AMP SoftLFO OPMonly
    with MMLChannel[Ch] do begin
//      if Enabled=True then begin
        if SLFONowDelay>=1 then begin
          SetOPMNoteNumber_V211(Ch,NowKeycode);
          SetOPMVolume_V211(Ch);
          dec(SLFONowDelay);
          end else begin
          if MPEnabled=True then begin
            case MPWaveType of
              0: begin // 櫛形
                inc(MPNowDetune,MPDisplace);
                dec(MPNowFreq);
                if MPNowFreq=0 then begin
                  MPNowFreq:=MPFreq;
                  MPNowDetune:=-MPNowDetune;
                end;
              end;
              1: begin // 矩形波
                if MPDisplace<0 then
                  MPNowDetune:=MPDisplace div 2
                  else
                  MPNowDetune:=MPDisplace;
                dec(MPNowFreq);
                if MPNowFreq=0 then begin
                  MPNowFreq:=MPFreq;
                  MPDisplace:=-MPDisplace;
                end;
              end;
              2: begin // 三角波
                inc(MPNowDetune,MPDisplace);
                dec(MPNowFreq);
                if MPNowFreq=0 then begin
                  MPNowFreq:=MPFreq;
                  MPDisplace:=-MPDisplace;
                end;
              end;
              3: begin // ランダム波
                dec(MPNowFreq);
                if MPNowFreq=0 then begin
                  MPNowFreq:=MPFreq;
                  tmp64:=Int64(MDX.SLFO3Param div $100)*Int64(MPDisplace);
                  if (-$7fff<=tmp64) and (tmp64<=$7fff) then begin
                    MPDisplace:=LongInt(tmp64);
                    end else begin
                    if tmp64<=-$7fff then begin
                      MPDisplace:=-$7fff;
                      end else begin
                      MPDisplace:=$7fff;
                    end;
                  end;
                end;
              end;
            end;
            SetOPMNoteNumber_V211(Ch,NowKeycode);
          end;
          if MAEnabled=True then begin
            case MAWaveType of
              0: begin // 櫛形
                inc(MANowDetune,MADisplace); // DeltaCooked
                dec(MANowFreq);
                if MANowFreq=0 then begin
                  MANowFreq:=MAFreq;
                  if MADisplace<=0 then begin
                    MANowDetune:=0;
                    end else begin
                    MANowDetune:=-MADisplace*MAFreq;
                  end;
                end;
              end;
              1: begin // 矩形波
                dec(MANowFreq);
                if MANowFreq=0 then begin
                  MANowFreq:=MAFreq;
                  if MADisplace<0 then
                    MANowDetune:=MADisplace
                    else
                    MANowDetune:=0;
                  MADisplace:=-MADisplace;
                end;
              end;
              2: begin // 三角波
                inc(MANowDetune,MADisplace);
                dec(MANowFreq);
                if MANowFreq=0 then begin
                  MANowFreq:=MAFreq;
                  MADisplace:=-MADisplace;
                end;
              end;
              3: begin // ランダム波
                dec(MANowFreq);
                if MANowFreq=0 then begin
                  MANowFreq:=MAFreq;
                  tmp64:=Int64(MDX.SLFO3Param div $100)*Int64(MADisplace);
                  if (-$7fff<=tmp64) and (tmp64<=$7fff) then begin
                    MADisplace:=LongInt(tmp64);
                    end else begin
                    if tmp64<=-$7fff then begin
                      MADisplace:=-$7fff;
                      end else begin
                      MADisplace:=$7fff;
                    end;
                  end;
                end;
              end;
            end;
            SetOPMVolume_V211(Ch);
          end;
        end;
      end;
//    end;
  end;
end;

procedure TMXDRVmDLL.ProcessFadeout;
begin
  with MDX do begin
    if FadeoutFlag=True then begin
      dec(MasterVolume);
      X68Sound_TotalVolume(MasterVolume);
      if MasterVolume=$00 then begin
        MDX.FadeoutFlag:=False;
        MDX.EndFlag:=True;
      end;
    end;
  end;
end;

function TMXDRVmDLL.GetMMLCommand(Ch:byte):boolean;
begin
  with MMLChannel[Ch] do begin
    if (NowPos<=MMLSize) and (Buffer<>nil) then begin // MMLSize+8までは$f1が入っている。
      Cmd[0]:=Buffer[NowPos+0];
      Cmd[1]:=Buffer[NowPos+1];
      Cmd[2]:=Buffer[NowPos+2];
      Cmd[3]:=Buffer[NowPos+3];
      Cmd[4]:=Buffer[NowPos+4];
      Cmd[5]:=Buffer[NowPos+5];
      end else begin
      Cmd[0]:=$f1;
      InfomationVisible('Channel.'+IntToStr(Ch+1)+' ErrorStop.');
      Enabled:=False;
      Result:=False;
      exit;
    end;
  end;
  Result:=True;
end;

procedure TMXDRVmDLL.RefTempo;
var
  SetTempo:integer;
begin
  SetTempo:=integer(MDX.Tempo)+TransTempo;
  if SetTempo<$00 then SetTempo:=$00;
  if SetTempo>$FF then SetTempo:=$FF;
  X68Sound_OPMSet($12,byte(SetTempo));
end;

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------

procedure TMXDRVmDLL.MMLAnalize_V210(Ch:byte;EnabledNoteon:boolean);
var
  OPMMode:boolean; // True=OPM False=ADPCM
  SetKeyoffMode:boolean;
  SetPortament:Longint;
  LoopChk,LoopChkCnt:byte;
  LoopChkFlag:boolean;
  CmdCap:byte;
begin
  if Ch<=7 then
    OPMMode:=True
    else
    OPMMode:=False;

  SetKeyoffMode:=True;
  SetPortament:=0;

  CmdCap:=$ff;

  with MMLChannel[Ch] do begin
    while RestClock<=0 do begin
      dec(CmdCap);
      if CmdCap=0 then begin
        WriteDebugLog('Ch:'+IntToStr(ch)+' 暴走防止コマンド制限で演奏を中断しました。');
        Enabled:=False;
        exit;
      end;

      if GetMMLCommand(Ch)=False then exit;
      inc(NowPos);

      if Cmd[0]<=$7f then begin // Rest offing
        inc(RestClock,Cmd[0]+1);
        Portament:=0;
        NowPortament:=0;
        StopClock:=0;
        Noteon:=False;
        if KeyoffMode then begin
          if EnabledNoteon then begin
            if OPMMode then
              SetOPMNoteoff(Ch)
              else
              SetADPCMNoteoff(Ch);
          end;
          NowKeycode:=0;
        end;
        SetKeyoffMode:=True;
        break;
      end;

      if ($80<=Cmd[0]) and (Cmd[0]<=$df) then begin // Set Noteon
        if Mute=False then Noteon:=True;
        Portament:=0;
        NowPortament:=0;
        if OPMMode then
          NowKeycode:=Cmd[0]-$80+3
          else
          NowKeycode:=Cmd[0]-$80+1;

        if QuartzMode then
          StopClock:=(LongInt(Cmd[1])-Quartz)+1
          else
          StopClock:=(LongInt(Cmd[1])*Quartz div 8)+1;

        if StopClock<=0 then StopClock:=1;

        if KeyoffMode=False then begin
          if OPMMode then
            SetOPMNoteNumber_V210(Ch,NowKeycode)
            else
            SetADPCMMode_V210(Ch,False);
          end else begin
          SLFONowDelay:=SLFODelay;

          if Mute=False then begin
            if EnabledNoteon then begin
              if OPMMode then begin
                SetOPMVolume_V210(Ch);
                SetOPMNoteon_V210(Ch,NowKeycode)
                end else begin
                SetADPCMMode_V210(Ch,True);
              end;
            end;
          end;
        end;
        inc(RestClock,Cmd[1]+1);
        inc(NowPos);
        break;
      end;

      case Cmd[0] of
        $ff: begin // Set Tempo
          MDX.Tempo:=Cmd[1];
          RefTempo;
          inc(NowPos);
        end;
        $fe: begin // Set OPM Register
          if ((2<=Cmd[1]) and (Cmd[1]<=7)) then begin
            WriteDebugLog('$fe,'+inttostr(Cmd[1])+' notsupp ort extend y-port.');
            case Cmd[1] of
              2: WriteDebugLog('NAMCO/KONAMI Wave Memory LFO Depth?');
              3: WriteDebugLog('NAMCO/KONAMI Wave Memory LFO Speed?');
              4: WriteDebugLog('Multiple n/256 Tempo?');
              5: WriteDebugLog('Special Effect Switch?');
              6: WriteDebugLog('KONAMI Portament?');
              7: WriteDebugLog('KONAMI LFO?');
            end;
            end else begin
            X68Sound_OPMSet(Cmd[1], Cmd[2]);
          end;
          inc(NowPos,2);
        end;
        $fd: begin // Set VoiceNo.
          NowVoice:=Cmd[1];
          if OPMMode then SetOPMVoice_V210(Ch);
          inc(NowPos);
        end;
        $fc: begin // Set Panpot
          if (OPMMode=False) and (MDX.ExtendPCM8=False) then
            if (Cmd[1]<>0) and (Cmd[1]<>3) then
             WriteDebugLog('Error:PCMPanpot NoPCM8');
          NowPanpot:=Cmd[1];
          if NowPanpot>=4 then WriteDebugLog(format('$fc,$%2x Panpot Error',[Cmd[1]]));
          if OPMMode then X68Sound_OPMSet($20+Ch, (NowPanpot*64)+(OPMVoice[NowVoice].AF and 63));// PAN/AF
          inc(NowPos);
        end;
        $fb: begin // Set Volume
          if (OPMMode=False) and (MDX.ExtendPCM8=False) then begin
            WriteDebugLog('Error:PCMVolume NoPCM8');
            end else begin
            if Cmd[1]<16 then begin
              if OPMMode then
                Volume:=OPMVolTbl[Cmd[1]]
                else
                Volume:=Cmd[1]*8;
              if Volume>=128 then Volume:=127;
              VolMode:=False;
              end else begin
              Volume:=127-(Cmd[1]-$80);
              VolMode:=True;
            end;
            if EnabledNoteon then begin
              if OPMMode then
                SetOPMVolume_V210(Ch)
                else
                SetADPCMMode_V210(Ch,False);
            end;
          end;
          inc(NowPos);
        end;
        $fa: begin // Downto Volume
          if (OPMMode=False) and (MDX.ExtendPCM8=False) then begin
            WriteDebugLog('Error:PCMVolume NoPCM8');
            end else begin
            if VolMode=False then begin
              if Volume>=2 then dec(Volume,2); // 違うのだ〜〜〜〜〜〜〜〜〜〜！！！！！！！！
              end else begin
              if Volume>=1 then dec(Volume);
            end;
            if EnabledNoteon then begin
              if OPMMode then
                SetOPMVolume_V210(Ch)
                else
                SetADPCMMode_V210(Ch,False);
            end;
          end;
        end;
        $f9: begin // Upto Volume
          if (OPMMode=False) and (MDX.ExtendPCM8=False) then begin
            WriteDebugLog('Error:PCMVolume NoPCM8');
            end else begin
            if VolMode=False then begin
              if Volume<=125 then inc(Volume,2); // 違うのだ〜〜〜〜〜〜〜〜〜〜！！！！！！！！
              end else begin
              if Volume<=126 then inc(Volume);
            end;
            if EnabledNoteon then begin
              if OPMMode then
                SetOPMVolume_V210(Ch)
                else
                SetADPCMMode_V210(Ch,False);
            end;
          end;
        end;
        $f8: begin // Set Pronounce Percent
          if Cmd[1]<=8 then begin
            Quartz:=Cmd[1];
            QuartzMode:=False;
            end else begin
            Quartz:=128-(Cmd[1]-$80)+1;
            QuartzMode:=True;
          end;
          inc(NowPos);
        end;
        $f7: begin // Disable Keyoff
          SetKeyoffMode:=False;
        end;
        $f6: begin // Start Repert
          inc(LoopMax);
          if Cmd[1]=0 then
            LoopCount[LoopMax]:=255
            else
            LoopCount[LoopMax]:=Cmd[1]-1;
          inc(NowPos,2);
        end;
        $f5: begin // End Repert
          if LoopCount[LoopMax]=0 then begin
            if LoopMax=0 then begin
              WriteDebugLog('EndRepert範囲外');
              Enabled:=False;
              end else begin
              dec(LoopMax);
            end;
            inc(NowPos,2);
            end else begin
            dec(LoopCount[LoopMax]);
            dec(NowPos,dword($FFFF)-dword(dword(Cmd[1])*$100+dword(Cmd[2]))-1);
          end;
        end;
        $f4: begin // Exit Repert
          if LoopCount[LoopMax]=0 then begin
            dec(LoopMax);
            inc(NowPos,dword(Cmd[1])*$100+dword(Cmd[2])+4);
            end else begin
            inc(NowPos,2);
          end;
        end;
        $f3: begin // Set Detune
          Detune:=SmallInt(dword(Cmd[1])*$100+Cmd[2]);
          if (OPMMode=False) and (Detune<>0) then WriteDebugLog('$f3 not support SetDetune in ADPCM');
          if OPMMode then SetOPMNoteNumber_V210(Ch,NowKeycode);
          inc(NowPos,2);
        end;
        $f2: begin // Set Portament
          NowPortament:=0;
          SetPortament:=SmallInt(dword(Cmd[1])*$100+Cmd[2]);
          if (OPMMode=False) and (SetPortament<>0) then WriteDebugLog('$f2 not support SetPortament in ADPCM');
          inc(NowPos,2);
        end;
        $f1: begin // End of data
          Looped:=True;
          LoopChkFlag:=True;
          LoopChkCnt:=MDX.MaxChannel;
          for LoopChk:=0 to LoopChkCnt do
            if (MMLChannel[LoopChk].Enabled=True) and (MMLChannel[LoopChk].Looped=False) then
              LoopChkFlag:=False;
          if LoopChkFlag=True then begin
            inc(MDX.LoopCount);
            for LoopChk:=0 to LoopChkCnt do
              MMLChannel[LoopChk].Looped:=False;
          end;

          if Cmd[1]=$00 then begin
            if OPMMode then
              SetOPMNoteoff(Ch)
              else
              SetADPCMNoteoff(Ch);
            NowPanpot:=0;
            Enabled:=False;
            LoopChkFlag:=True;
            LoopChkCnt:=MDX.MaxChannel;
            for LoopChk:=0 to LoopChkCnt do
              if MMLChannel[LoopChk].Enabled=True then LoopChkFlag:=False;
            if LoopChkFlag=True then MDX.EndFlag:=True;
            end else begin
            if NowPos<(dword($FFFF)-(dword(Cmd[1])*$100+dword(Cmd[2]))-1) then begin
              WriteDebugLog('DataEndアドレス範囲外 addr:'+inttostr(NowPos)+'-'+inttostr((dword($FFFF)-(dword(Cmd[1])*$100+dword(Cmd[2]))-1)));
              Enabled:=False;
              MDX.EndFlag:=True;
              end else begin
              dec(NowPos,dword($FFFF)-(dword(Cmd[1])*$100+dword(Cmd[2]))-1);
            end;
          end;
        end;
        $f0: begin // Set Keyon Delay
          dec(RestClock,KeyonDelay);
          KeyonDelay:=Cmd[1];
          inc(RestClock,KeyonDelay);
          inc(NowPos);
        end;
        $ef: begin // Send Adjust Signal
          if Cmd[1]<=15 then
            MMLChannel[Cmd[1]].SignalWaitFlag:=True
            else
            WriteDebugLog('同期信号送信チャネル[Ch.'+IntToStr(Cmd[1]+1)+'] 範囲外');
          inc(NowPos);
        end;
        $ee: begin // Waiting Adjust Signal
          SignalWaitFlag:=False;
        end;
        $ed: begin // Set Noize Frequency // Supported Ch.H only
          if OPMMode then begin
            if Cmd[1]=0 then
              Slot32Enabled:=False
              else
              Slot32Enabled:=True;
            X68Sound_OPMSet($0f, Cmd[1]);
            end else begin
            ADPCMRate:=Cmd[1];
            SetADPCMMode_V210(Ch,False);
          end;
          inc(NowPos);
        end;
        $ec: begin // Set Tone LFO V210
          MPNowFreq:=1;
          MPNowCount:=0;
          MPNowDetune:=0;
          MPDisplace:=MPMstDisplace;
          case Cmd[1] of
            $80: begin
              MPEnabled:=False;
              inc(NowPos);
            end;
            $81: begin
              if MPDisplace<>0 then MPEnabled:=True;
              inc(NowPos);
            end;
            else begin
              inc(NowPos,5);
              if OPMMode then begin
                if Cmd[1]>=8 then begin
                  WriteDebugLog('$eb NotSupported PhaseLFO Type');
                  WriteDebugLog(format('$%2x,%2x,%2x,%2x,%2x',[Cmd[1],Cmd[2],Cmd[3],Cmd[4],Cmd[5]]));
                  if Cmd[1]=$08 then WriteDebugLog('NamcoWaveMemory?');
                  if Cmd[1]=$09 then WriteDebugLog('KonamiWaveMemory?');
                  MPEnabled:=False;
                  exit;
                end;
                MPEnabled:=True;
                MPWaveType:=Cmd[1] mod 4;
                MPFreq:=Cmd[2]*$100+Cmd[3]+2;
                if MPWaveType=1 then MPFreq:=MPFreq div 2; // Type1は/2で良いのかどうか確認する
                if MPWaveType=2 then MPFreq:=MPFreq div 2;
                MPDisplace:=SmallInt(dword(Cmd[4])*$100+Cmd[5]);
                if MPWaveType=2 then MPDisplace:=-MPDisplace; // Type1は大丈夫？
                MPMstDisplace:=MPDisplace;
                if (Cmd[1] and 4)=4 then MPDisplace:=MPDisplace*$100;
                if MPDisplace=0 then MPEnabled:=False;
                MPDisplace:=MPDisplace div 2;
                end else begin
                WriteDebugLog('$ec not support Tone(Phase)LFO in ADPCM');
              end;
            end;
          end;
        end;
        $eb: begin // Set Volume LFO V210
          MANowFreq:=1;
          MANowCount:=0;
          MANowDetune:=0;
          MADisplace:=MAMstDisplace;
          case Cmd[1] of
            $80: begin
              MAEnabled:=False;
              inc(NowPos);
            end;
            $81: begin
              if MADisplace<>0 then MAEnabled:=True;
              inc(NowPos);
            end;
            else begin
              inc(NowPos,5);
              if OPMMode then begin
                if Cmd[1]>=8 then begin
                  WriteDebugLog('$eb NotSupported AMPLFO Type');
                  WriteDebugLog(format('$%2x,%2x,%2x,%2x,%2x',[Cmd[1],Cmd[2],Cmd[3],Cmd[4],Cmd[5]]));
                  MAEnabled:=False;
                  exit;
                end;
                MAEnabled:=True;
                MAWaveType:=Cmd[1] mod 4;
                MAFreq:=Cmd[2]*$100+Cmd[3]+2;
                if MAWaveType=1 then MAFreq:=MAFreq div 2; // Type1は/2で良いみたい
                if MAWaveType=2 then MAFreq:=MAFreq div 2;
                MADisplace:=-SmallInt(dword(Cmd[4])*$100+Cmd[5]); // 符号反転しなくても平気？
                MAMstDisplace:=MADisplace;
                if (Cmd[1] and 4)=4 then MADisplace:=MADisplace*$100;
                if MADisplace=0 then MAEnabled:=False;
                end else begin
                WriteDebugLog('$eb not support Volume(AMP)LFO in ADPCM');
              end;
            end;
          end;
        end;
        $ea: begin // Set OPM LFO
          if OPMMode then begin
            case Cmd[1] of
              $80: begin
                X68Sound_OPMSet($38+ch, 0); // MHOF PMS/AMS
                NowPAMSEnabled:=False;
                inc(NowPos);
              end;
              $81: begin
                X68Sound_OPMSet($38+ch, NowPAMS); // MHON PMS/AMS
                NowPAMSEnabled:=True;
                inc(NowPos);
              end;
              else begin
                inc(NowPos,5);
                if (Cmd[1] and $40)=$40 then
                  NowSync:=True
                  else
                  NowSync:=False;
                X68Sound_OPMSet($1b, Cmd[1] and 3);        // WaveForm
                X68Sound_OPMSet($18, Cmd[2]);		    // LFREQ
                X68Sound_OPMSet($19, $80+(Cmd[3] and $7f));// PMD
                X68Sound_OPMSet($19, (Cmd[4] and $7f));    // AMD
                X68Sound_OPMSet($38+ch, Cmd[5]);           // PMS/AMS
                NowPAMSEnabled:=True;
                NowPAMS:=Cmd[5];
              end;
            end;
            end else begin // ADPCM
            WriteDebugLog('$ea not support OPMLFO in ADPCM');
            if (Cmd[1]=$80) or (Cmd[1]=$81) then begin
              inc(NowPos);
              end else begin
              inc(NowPos,5);
            end;
          end;
        end;
        $e9: begin // Set LFO Delay
          SLFODelay:=Cmd[1]+1;
          inc(NowPos);
        end;
        $e8: begin // Set Expanded PCM8 Mode
        end;
        $e7: begin // Start Fadeout
          case Cmd[1] of
            $00: begin
              WriteDebugLog('$e7,00 data error.');
              inc(NowPos);
            end;
            $01: begin
              MDX.FadeoutFlag:=True;
              // Cmd[2] of FadeoutSpeed not use.
              inc(NowPos,2);
            end;
            else begin
              Enabled:=False;
              WriteDebugLog('$e7 unknown extend.');
              WriteDebugLog(format('$%2x,%2x,%2x,%2x,%2x',[Cmd[1],Cmd[2],Cmd[3],Cmd[4],Cmd[5]]));
              case Cmd[1] of
                $02: WriteDebugLog('DirectDrive PCM8?');
                $03: WriteDebugLog('Enabled Q command?');
                $04: WriteDebugLog('EtcChannel Control?');
                $05: WriteDebugLog('Add ToneLength?');
                $06: WriteDebugLog('DualPCM mxdrv15p?');
                else WriteDebugLog('Unknown Param?');
              end;
            end;
          end;
        end;
        $e6: begin // Extend Command mxdrv16x system
          Enabled:=False;
          if Cmd[1]=$00 then begin
            WriteDebugLog('$e6,00 data error.');
            end else begin
            WriteDebugLog('$e6 unknown extend.');
            WriteDebugLog(format('$%2x,%2x,%2x,%2x,%2x',[Cmd[1],Cmd[2],Cmd[3],Cmd[4],Cmd[5]]));
            case Cmd[1] of
              $01: WriteDebugLog('Detune?');
              $02: WriteDebugLog('DirectTransport?');
              $03: WriteDebugLog('Transport?');
              $04: WriteDebugLog('DirectMasterVolume?');
              $05: WriteDebugLog('MasterVolume?');
              $06: WriteDebugLog('Fadein/out Flag?');
            end;
          end;
        end;

        else begin
          if $e0<=Cmd[0] then begin
            Enabled:=False;
            WriteDebugLog(format('$%2x unkown extend',[Cmd[0]]));
            WriteDebugLog(format('$%2x,%2x,%2x,%2x,%2x',[Cmd[1],Cmd[2],Cmd[3],Cmd[4],Cmd[5]]));
          end;
        end;
      end;
    end;
  end;

  with MMLChannel[Ch] do begin
    KeyoffMode:=SetKeyoffMode;
    Portament:=SetPortament;
    if Portament=0 then NowPortament:=0;
  end;
end;

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------

procedure TMXDRVmDLL.MMLAnalize_V211(Ch:byte;EnabledNoteon:boolean);
var
  OPMMode:boolean; // True=OPM False=ADPCM
  SetKeyoffMode:boolean;
  SetPortament:Longint;
  LoopChk,LoopChkCnt:byte;
  LoopChkFlag:boolean;
  CmdCap:byte;
begin
  if Ch<=7 then
    OPMMode:=True
    else
    OPMMode:=False;

  SetKeyoffMode:=True;
  SetPortament:=0;

  CmdCap:=$ff;

  with MMLChannel[Ch] do begin
    while RestClock<=0 do begin
      dec(CmdCap);
      if CmdCap=0 then begin
        WriteDebugLog('Ch:'+IntToStr(ch)+' 暴走防止コマンド制限で演奏を中断しました。');
        Enabled:=False;
        exit;
      end;

      if GetMMLCommand(Ch)=False then exit;
      inc(NowPos);

      if Cmd[0]<=$7f then begin // Rest offing
        inc(RestClock,Cmd[0]+1);
        Portament:=0;
        NowPortament:=0;
        StopClock:=0;
        Noteon:=False;
        if KeyoffMode then begin
          if EnabledNoteon then begin
            if OPMMode then
              SetOPMNoteoff(Ch)
              else
              SetADPCMNoteoff(Ch);
          end;
          NowKeycode:=0;
        end;
        SetKeyoffMode:=True;
        break;
      end;

      if ($80<=Cmd[0]) and (Cmd[0]<=$df) then begin // Set Noteon
        if Mute=False then Noteon:=True;
        Portament:=0;
        NowPortament:=0;
        if OPMMode then
          NowKeycode:=Cmd[0]-$80+3
          else
          NowKeycode:=Cmd[0]-$80+1;

        if QuartzMode then
          StopClock:=(LongInt(Cmd[1])-Quartz)+1
          else
          StopClock:=(LongInt(Cmd[1])*Quartz div 8)+1;

        if StopClock<=0 then StopClock:=1;

        if KeyoffMode=False then begin
          if OPMMode then begin
            SetOPMVoice_V211(Ch);
            SetOPMNoteNumber_V211(Ch,NowKeycode);
            end else begin
            SetADPCMMode_V211(Ch,False);
          end;
          end else begin
          SLFONowDelay:=SLFODelay;

          if Mute=False then begin
            if EnabledNoteon then begin
              if OPMMode then begin
                with OPMVoice[MMLChannel[Ch].NowVoice] do begin
                  X68Sound_OPMSet($20+Ch, (AF and 63));	// PAN/AF
                end;
                SetOPMNoteoff(Ch);
                SetOPMVoice_V211(Ch);
                SetOPMNoteon_V211(Ch,NowKeycode);
                with OPMVoice[MMLChannel[Ch].NowVoice] do begin
                  X68Sound_OPMSet($20+Ch, (MMLChannel[Ch].NowPanpot*64)+(AF and 63));	// PAN/AF
                end;
                end else begin
                SetADPCMMode_V211(Ch,True);
              end;
            end;
          end;
        end;
        inc(RestClock,Cmd[1]+1);
        inc(NowPos);
        break;
      end;

      case cmd[0] of
        $ff: begin // Set Tempo
          MDX.Tempo:=Cmd[1];
          RefTempo;
          inc(NowPos);
        end;
        $fe: begin // Set OPM Register
          if ((2<=Cmd[1]) and (Cmd[1]<=7)) then begin
            WriteDebugLog('$fe,'+inttostr(Cmd[1])+' notsupport extend y-port.');
            case Cmd[1] of
              2: WriteDebugLog('NAMCO/KONAMI Wave Memory LFO Depth?');
              3: WriteDebugLog('NAMCO/KONAMI Wave Memory LFO Speed?');
              4: WriteDebugLog('Multiple n/256 Tempo?');
              5: WriteDebugLog('Special Effect Switch?');
              6: WriteDebugLog('KONAMI Portament?');
              7: WriteDebugLog('KONAMI LFO?');
            end;
            end else begin
            X68Sound_OPMSet(Cmd[1], Cmd[2]);
          end;
          inc(NowPos,2);
        end;
        $fd: begin // Set VoiceNo.
{$IFDEF UseDebugDriver}
          if (OPMMode=True) and (OPMVoice[Cmd[1]].Enabled=False) then begin
            WriteDebugLog('Error:音色定義されていない音色が使われています。'+format('Ch.%d No.%d',[Ch+1,Cmd[1]]));
          end;
          if (OPMMode=False) and (Cmd[1]>$7f) then begin
            WriteDebugLog('Error:128番目以降のADPCMバンクが指定されました。Bank0に再定義しました。'+format('Ch.%d No.%d',[Ch+1,Cmd[1]]));
          end;
{$ENDIF}
          if OPMMode=True then begin
            NowVoice:=Cmd[1];
          end;
          if OPMMode=False then begin
            NowVoice:=Cmd[1];
            if NowVoice>$7F then NowVoice:=0;
          end;
          inc(NowPos);
        end;
        $fc: begin // Set Panpot
{$IFDEF UseDebugDriver}
          if (OPMMode=False) and (MDX.ExtendPCM8=False) then
            if (Cmd[1]<>0) and (Cmd[1]<>3) then
             WriteDebugLog('Error:PCMPanpot NoPCM8');
{$ENDIF}
          NowPanpot:=Cmd[1];
          if EnabledNoteon then begin
            if OPMMode then
              X68Sound_OPMSet($20+Ch, (NowPanpot*64)+(OPMVoice[NowVoice].AF and 63)) // PAN/AF
              else
              SetADPCMMode_V211(Ch,False);
          end;
          inc(NowPos);
        end;
        $fb: begin // Set Volume
{$IFDEF UseDebugDriver}
          if (OPMMode=False) and (MDX.ExtendPCM8=False) then begin
            WriteDebugLog('Error:PCMVolume NoPCM8');
          end;
{$ENDIF}
          if Cmd[1]<$80 then begin
            Volume:=Cmd[1];
{$IFDEF UseDebugDriver}
            if Volume>$0f then WriteDebugLog('VolumeError:'+inttostr(Ch)+' v'+inttostr(Volume));
{$ENDIF}
            if Volume>$0f then Volume:=$0f;
            VolMode:=False;
            end else begin
            Volume:=127-(Cmd[1]-$80);
            if Volume>$7f then Volume:=$7f;
            VolMode:=True;
          end;
          if EnabledNoteon then begin
            if OPMMode then
              SetOPMVolume_V211(Ch)
              else
              SetADPCMMode_V211(Ch,False);
          end;
          inc(NowPos);
        end;
        $fa: begin // Downto Volume
{$IFDEF UseDebugDriver}
          if (OPMMode=False) and (MDX.ExtendPCM8=False) then begin
            WriteDebugLog('Error:PCMVolume NoPCM8');
          end;
{$ENDIF}
          if VolMode=False then begin
            if Volume>=1 then dec(Volume);
            end else begin
            if Volume>=1 then dec(Volume);
          end;
          if EnabledNoteon then begin
            if OPMMode then
              SetOPMVolume_V211(Ch)
              else
              SetADPCMMode_V211(Ch,False);
          end;
        end;
        $f9: begin // Upto Volume
{$IFDEF UseDebugDriver}
          if (OPMMode=False) and (MDX.ExtendPCM8=False) then begin
            WriteDebugLog('Error:PCMVolume NoPCM8');
          end;
{$ENDIF}
          if VolMode=False then begin
            if Volume<=14 then inc(Volume);
            end else begin
            if Volume<=126 then inc(Volume);
          end;
          if EnabledNoteon then begin
            if OPMMode then
              SetOPMVolume_V211(Ch)
              else
              SetADPCMMode_V211(Ch,False);
          end;
        end;
        $f8: begin // Set Pronounce Percent
          if Cmd[1]<=8 then begin
            Quartz:=Cmd[1];
            QuartzMode:=False;
            end else begin
            Quartz:=128-(Cmd[1]-$80)+1;
            QuartzMode:=True;
          end;
          inc(NowPos);
        end;
        $f7: begin // Disable Keyoff
          SetKeyoffMode:=False;
        end;
        $f6: begin // Start Repert
          inc(LoopMax);
          if Cmd[1]=0 then
            LoopCount[LoopMax]:=255
            else
            LoopCount[LoopMax]:=Cmd[1]-1;
          inc(NowPos,2);
        end;
        $f5: begin // End Repert
          if LoopCount[LoopMax]=0 then begin
            if LoopMax=0 then begin
              WriteDebugLog('EndRepert範囲外');
              Enabled:=False;
              end else begin
              dec(LoopMax);
            end;
            inc(NowPos,2);
            end else begin
            dec(LoopCount[LoopMax]);
            dec(NowPos,dword($FFFF)-dword(dword(Cmd[1])*$100+dword(Cmd[2]))-1);
          end;
        end;
        $f4: begin // Exit Repert
          if LoopCount[LoopMax]=0 then begin
            if LoopMax=0 then begin
              WriteDebugLog('Loop対Exitコマンドの数が同じではありません');
              Enabled:=False;
              end else begin
              dec(LoopMax);
              inc(NowPos,dword(Cmd[1])*$100+dword(Cmd[2])+4);
            end;
            end else begin
            inc(NowPos,2);
          end;
        end;
        $f3: begin // Set Detune
          Detune:=SmallInt(dword(Cmd[1])*$100+Cmd[2]);
          if (OPMMode=False) and (Detune<>0) then WriteDebugLog('$f3 not support SetDetune in ADPCM');
          if OPMMode then SetOPMNoteNumber_V211(Ch,NowKeycode);
          inc(NowPos,2);
        end;
        $f2: begin // Set Portament
          NowPortament:=0;
          SetPortament:=SmallInt(dword(Cmd[1])*$100+Cmd[2]);
          if (OPMMode=False) and (SetPortament<>0) then WriteDebugLog('$f2 not support SetPortament in ADPCM');
          inc(NowPos,2);
        end;
        $f1: begin // End of data
          Looped:=True;
          LoopChkFlag:=True;
          LoopChkCnt:=MDX.MaxChannel;
          for LoopChk:=0 to LoopChkCnt do
            if (MMLChannel[LoopChk].Enabled=True) and (MMLChannel[LoopChk].Looped=False) then
              LoopChkFlag:=False;
          if LoopChkFlag=True then begin
            inc(MDX.LoopCount);
            for LoopChk:=0 to LoopChkCnt do
              MMLChannel[LoopChk].Looped:=False;
          end;

          if Cmd[1]=$00 then begin
            if OPMMode then
              SetOPMNoteoff(Ch)
              else
              SetADPCMNoteoff(Ch);
            NowPanpot:=0;
            Enabled:=False;
            LoopChkFlag:=True;
            LoopChkCnt:=MDX.MaxChannel;
            for LoopChk:=0 to LoopChkCnt do
              if MMLChannel[LoopChk].Enabled=True then LoopChkFlag:=False;
            if LoopChkFlag=True then MDX.EndFlag:=True;
            end else begin
            if NowPos<(dword($FFFF)-(dword(Cmd[1])*$100+dword(Cmd[2]))-1) then begin
              WriteDebugLog('DataEndアドレス範囲外 addr:'+inttostr(NowPos)+'-'+inttostr((dword($FFFF)-(dword(Cmd[1])*$100+dword(Cmd[2]))-1)));
              Enabled:=False;
              MDX.EndFlag:=True;
              end else begin
              dec(NowPos,dword($FFFF)-(dword(Cmd[1])*$100+dword(Cmd[2]))-1);
            end;
          end;
        end;
        $f0: begin // Set Keyon Delay
          dec(RestClock,KeyonDelay);
          KeyonDelay:=Cmd[1];
          inc(RestClock,KeyonDelay);
          inc(NowPos);
        end;
        $ef: begin // Send Adjust Signal
{$IFDEF UseDebugDriver}
          if Cmd[1]>=16 then WriteDebugLog('同期信号送信チャネル[Ch.'+IntToStr(Cmd[1]+1)+'] 範囲外');
{$ENDIF}
          if Cmd[1]<=15 then MMLChannel[Cmd[1]].SetSignalWaitFlag:=True;
{
          test.lst.Items.Add(format('%5d/%2d ',[(MDX.TotalClock-1),(MDX.TotalClock-1) mod 48])+'SendSignal '+copy('ABCDEFGHIJKLMNOPQRSTU',ch+1,1)+'->'+copy('ABCDEFGHIJKLMNOPQRSTU',cmd[1]+1,1));
          test.Visible:=True;
          test.Refresh;
}
          inc(NowPos,1);
        end;
        $ee: begin // Waiting Adjust Signal
          SignalWaitFlag:=False;
{
          test.lst.Items.Add(format('%5d/%2d ',[(MDX.TotalClock-1),(MDX.TotalClock-1) mod 48])+'Waiting Signal '+copy('ABCDEFGHIJKLMNOPQRSTU',ch+1,1));
          test.Visible:=True;
          test.Refresh;
}
          break;
        end;
        $ed: begin // Set Noize Frequency // Supported Ch.H only
          if OPMMode then begin
            if Cmd[1]=0 then
              Slot32Enabled:=False
              else
              Slot32Enabled:=True;
            X68Sound_OPMSet($0f, Cmd[1]);
            end else begin
            ADPCMRate:=Cmd[1];
            SetADPCMMode_V211(Ch,False);
          end;
          inc(NowPos);
        end;
        $ec: begin // Set Tone LFO V211
          MPNowFreq:=1;
          MPNowCount:=0;
          MPNowDetune:=0;
          MPDisplace:=MPMstDisplace;
          case Cmd[1] of
            $80: begin
              MPEnabled:=False;
              inc(NowPos);
            end;
            $81: begin
              if MPDisplace<>0 then MPEnabled:=True;
              inc(NowPos);
            end;
            else begin
              inc(NowPos,5);
              if OPMMode then begin
                if Cmd[1]>=8 then begin
                  WriteDebugLog('$eb NotSupported PhaseLFO Type');
                  WriteDebugLog(format('$%2x,%2x,%2x,%2x,%2x',[Cmd[1],Cmd[2],Cmd[3],Cmd[4],Cmd[5]]));
                  if Cmd[1]=$08 then WriteDebugLog('NamcoWaveMemory?');
                  if Cmd[1]=$09 then WriteDebugLog('KonamiWaveMemory?');
                  MPEnabled:=False;
                  exit;
                end;
                MPEnabled:=True;
                MPWaveType:=Cmd[1] mod 4;
                MPFreq:=Cmd[2]*$100+Cmd[3]+2;
                if MPWaveType=0 then MPFreq:=MPFreq div 2;
                MPDisplace:=SmallInt(dword(Cmd[4])*$100+Cmd[5]);
                if MPWaveType=1 then MPDisplace:=-MPDisplace;
                if (Cmd[1] and 4)=4 then MPDisplace:=MPDisplace*$100;
                MPMstDisplace:=MPDisplace;
                if MPDisplace=0 then MPEnabled:=False;
                end else begin
{$IFDEF UseDebugDriver}
                WriteDebugLog('$ec not support Tone(Phase)LFO in ADPCM');
{$ENDIF}
              end;
            end;
          end;
          if OPMMode then SetOPMMPInit_V211(Ch);
        end;
        $eb: begin // Set Volume LFO V211
          case Cmd[1] of
            $80: begin
              MAEnabled:=False;
              inc(NowPos);
            end;
            $81: begin
              if MADisplace<>0 then MAEnabled:=True;
              inc(NowPos);
            end;
            else begin
              inc(NowPos,5);
              if OPMMode then begin
                if Cmd[1]>=8 then begin
                  WriteDebugLog('$eb NotSupported AMPLFO Type');
                  WriteDebugLog(format('$%2x,%2x,%2x,%2x,%2x',[Cmd[1],Cmd[2],Cmd[3],Cmd[4],Cmd[5]]));
                  MAEnabled:=False;
                  exit;
                end;
                MAEnabled:=True;
                MAWaveType:=Cmd[1] mod 4;
                MAFreq:=Cmd[2]*$100+Cmd[3]+2;
                MADisplace:=SmallInt(dword(Cmd[4])*$100+Cmd[5]);
                if MAWaveType=0 then MADisplace:=-MADisplace;
                if (Cmd[1] and 4)=4 then MADisplace:=MADisplace*$100;
                MAMstDisplace:=MADisplace;
//                if MAWaveType=2 then MAFreq:=MAFreq div 2;
                if MADisplace=0 then MAEnabled:=False;
                end else begin
{$IFDEF UseDebugDriver}
                WriteDebugLog('$eb not support Volume(AMP)LFO in ADPCM');
{$ENDIF}
              end;
            end;
          end;
          if OPMMode then SetOPMMAInit_V211(Ch);
        end;
        $ea: begin // Set OPM LFO
          if OPMMode then begin
            case Cmd[1] of
              $80: begin
                X68Sound_OPMSet($38+ch, 0); // MHOF PMS/AMS
                NowPAMSEnabled:=False;
                inc(NowPos);
              end;
              $81: begin
                X68Sound_OPMSet($38+ch, NowPAMS); // MHON PMS/AMS
                NowPAMSEnabled:=True;
                inc(NowPos);
              end;
              else begin
                inc(NowPos,5);
                if (Cmd[1] and $40)=$40 then
                  NowSync:=True
                  else
                  NowSync:=False;
                X68Sound_OPMSet($1b, Cmd[1] and 3);        // WaveForm
                X68Sound_OPMSet($18, Cmd[2]);		    // LFREQ
                X68Sound_OPMSet($19, $80+(Cmd[3] and $7f));// PMD
                X68Sound_OPMSet($19, (Cmd[4] and $7f));    // AMD
                X68Sound_OPMSet($38+ch, Cmd[5]);           // PMS/AMS
                NowPAMSEnabled:=True;
                NowPAMS:=Cmd[5];
              end;
            end;
            end else begin // ADPCM
{$IFDEF UseDebugDriver}
            WriteDebugLog('$ea not support OPMLFO in ADPCM');
{$ENDIF}
            if (Cmd[1]=$80) or (Cmd[1]=$81) then begin
              inc(NowPos);
              end else begin
              inc(NowPos,5);
            end;
          end;
        end;
        $e9: begin // Set LFO Delay
          SLFODelay:=Cmd[1];
          inc(NowPos);
        end;
        $e8: begin // Set Expanded PCM8 Mode
        end;
        $e7: begin // Start Fadeout
          case Cmd[1] of
            $00: WriteDebugLog('$e7,00 data error.');
            $01: begin
              MDX.FadeoutFlag:=True;
              // Cmd[2] of FadeoutSpeed not use.
              inc(NowPos,2);
            end;
            else begin
              Enabled:=False;
              WriteDebugLog('$e7 unknown extend.');
              WriteDebugLog(format('$%2x,%2x,%2x,%2x,%2x',[Cmd[1],Cmd[2],Cmd[3],Cmd[4],Cmd[5]]));
              case Cmd[1] of
                $02: WriteDebugLog('DirectDrive PCM8?');
                $03: WriteDebugLog('Enabled Q command?');
                $04: WriteDebugLog('EtcChannel Control?');
                $05: WriteDebugLog('Add ToneLength?');
                $06: WriteDebugLog('DualPCM mxdrv15p?');
                else WriteDebugLog('Unknown Param?');
              end;
            end;
          end;
        end;
        $e6: begin // Extend Command mxdrv16x system
          Enabled:=False;
          if Cmd[1]=$00 then begin
            WriteDebugLog('$e6,00 data error.');
            end else begin
            WriteDebugLog('$e6 unknown extend.');
            WriteDebugLog(format('$%2x,%2x,%2x,%2x,%2x',[Cmd[1],Cmd[2],Cmd[3],Cmd[4],Cmd[5]]));
            case Cmd[1] of
              $01: WriteDebugLog('Detune?');
              $02: WriteDebugLog('DirectTransport?');
              $03: WriteDebugLog('Transport?');
              $04: WriteDebugLog('DirectMasterVolume?');
              $05: WriteDebugLog('MasterVolume?');
              $06: WriteDebugLog('Fadein/out Flag?');
            end;
          end;
        end;

        else begin
          if $e0<=Cmd[0] then begin
            Enabled:=False;
            WriteDebugLog(format('$%2x unkown extend',[Cmd[0]]));
            WriteDebugLog(format('$%2x,%2x,%2x,%2x,%2x',[Cmd[1],Cmd[2],Cmd[3],Cmd[4],Cmd[5]]));
          end;
        end;
      end;
    end;
  end;

  with MMLChannel[Ch] do begin
    KeyoffMode:=SetKeyoffMode;
    Portament:=SetPortament;
    if Portament=0 then NowPortament:=0;
  end;
end;

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------

procedure TMXDRVmDLL.MMLAnalizeForMesure(Ch:byte);
var
  OPMMode:boolean; // True=OPM False=ADPCM
  LoopChk,LoopChkCnt:byte;
  LoopChkFlag:boolean;
  CmdCap:byte;
begin
  if Ch<=7 then
    OPMMode:=True
    else
    OPMMode:=False;

  CmdCap:=$ff; // 無限暴走しないように1clock内に255回処理したら演奏停止

  with MMLChannel[Ch] do begin
    while RestClock<=0 do begin
      dec(CmdCap);
      if CmdCap=0 then begin
        WriteDebugLog('Ch:'+IntToStr(ch)+' 暴走防止コマンド制限で解析を中断しました。');
        Enabled:=False;
        exit;
      end;

      if GetMMLCommand(Ch)=False then exit;
      inc(NowPos);

      if Cmd[0]<=$7f then begin // Rest offing
        inc(RestClock,Cmd[0]+1);
        StopClock:=0;
        break;
      end;

      if ($80<=Cmd[0]) and (Cmd[0]<=$df) then begin // Set Noteon
        inc(RestClock,Cmd[1]);
        inc(RestClock);
        inc(NowPos);
        break;
      end;

      case Cmd[0] of
        $ff: begin // Set Tempo
          inc(NowPos);
        end;
        $fe: begin // Set OPM Register
          inc(NowPos,2);
        end;
        $fd: begin // Set VoiceNo.
          inc(NowPos);
        end;
        $fc: begin // Set Panpot
          inc(NowPos);
        end;
        $fb: begin // Set Volume
          inc(NowPos);
        end;
        $fa: begin // Downto Volume
        end;
        $f9: begin // Upto Volume
        end;
        $f8: begin // Set Pronounce Percent
          inc(NowPos);
        end;
        $f7: begin // Disable Keyoff
        end;
        $f6: begin // Start Repert
          inc(LoopMax);
          if Cmd[1]=0 then
            LoopCount[LoopMax]:=255
            else
            LoopCount[LoopMax]:=Cmd[1]-1;
          inc(NowPos,2);
        end;
        $f5: begin // End Repert
          if LoopCount[LoopMax]=0 then begin
            if LoopMax=0 then begin
              WriteDebugLog('EndRepert範囲外');
              Enabled:=False;
              end else begin
              dec(LoopMax);
            end;
            inc(NowPos,2);
            end else begin
            dec(LoopCount[LoopMax]);
            dec(NowPos,dword($FFFF)-dword(dword(Cmd[1])*$100+dword(Cmd[2]))-1);
          end;
        end;
        $f4: begin // Exit Repert
          if LoopCount[LoopMax]=0 then begin
            if LoopMax=0 then begin
              WriteDebugLog('Loop対Exitコマンドの数が同じではありません');
              Enabled:=False;
              end else begin
              dec(LoopMax);
              inc(NowPos,dword(Cmd[1])*$100+dword(Cmd[2])+4);
            end;
            end else begin
            inc(NowPos,2);
          end;
        end;
        $f3: begin // Set Detune
          if (OPMMode=False) and (SmallInt(dword(Cmd[1])*$100+Cmd[2])<>0) then WriteDebugLog('$f3 not support SetDetune in ADPCM');
          inc(NowPos,2);
        end;
        $f2: begin // Set Portament
          if (OPMMode=False) and (SmallInt(dword(Cmd[1])*$100+Cmd[2])<>0) then WriteDebugLog('$f2 not support SetPortament in ADPCM');
          inc(NowPos,2);
        end;
        $f1: begin // End of data
          Looped:=True;
          LoopChkFlag:=True;
          LoopChkCnt:=MDX.MaxChannel;
          for LoopChk:=0 to LoopChkCnt do
            if (MMLChannel[LoopChk].Enabled=True) and (MMLChannel[LoopChk].Looped=False) then
              LoopChkFlag:=False;
          if LoopChkFlag=True then begin
            inc(MDX.LoopCount);
            for LoopChk:=0 to LoopChkCnt do
              MMLChannel[LoopChk].Looped:=False;
          end;

          if Cmd[1]=$00 then begin
            if OPMMode then
              SetOPMNoteoff(Ch)
              else
              SetADPCMNoteoff(Ch);
            NowPanpot:=0;
            Enabled:=False;
            LoopChkFlag:=True;
            LoopChkCnt:=MDX.MaxChannel;
            for LoopChk:=0 to LoopChkCnt do
              if MMLChannel[LoopChk].Enabled=True then LoopChkFlag:=False;
            if LoopChkFlag=True then MDX.EndFlag:=True;
            end else begin
            if NowPos<(dword($FFFF)-(dword(Cmd[1])*$100+dword(Cmd[2]))-1) then begin
              WriteDebugLog('DataEndアドレス範囲外 addr:'+inttostr(NowPos)+'-'+inttostr((dword($FFFF)-(dword(Cmd[1])*$100+dword(Cmd[2]))-1)));
              Enabled:=False;
              MDX.EndFlag:=True;
              end else begin
              dec(NowPos,dword($FFFF)-(dword(Cmd[1])*$100+dword(Cmd[2]))-1);
            end;
          end;
        end;
        $f0: begin // Set Keyon Delay
          dec(RestClock,KeyonDelay);
          KeyonDelay:=Cmd[1];
          inc(RestClock,KeyonDelay);
          inc(NowPos);
        end;
        $ef: begin // Send Adjust Signal
          if Cmd[1]<=15 then MMLChannel[Cmd[1]].SetSignalWaitFlag:=True;
          inc(NowPos);
        end;
        $ee: begin // Waiting Adjust Signal
          SignalWaitFlag:=False;
          break;
        end;
        $ed: begin // Set Noize Frequency // Supported Ch.H only
          inc(NowPos);
        end;
        $ec: begin // Set Tone LFO
          case Cmd[1] of
            $80: begin
              inc(NowPos);
            end;
            $81: begin
              inc(NowPos);
            end;
            else begin
              inc(NowPos,5);
            end;
          end;
        end;
        $eb: begin // Set Volume LFO
          case Cmd[1] of
            $80: begin
              inc(NowPos);
            end;
            $81: begin
              inc(NowPos);
            end;
            else begin
              inc(NowPos,5);
            end;
          end;
        end;
        $ea: begin // Set OPM LFO
          if OPMMode then begin
            case Cmd[1] of
              $80: begin
                inc(NowPos);
              end;
              $81: begin
                inc(NowPos);
              end;
              else begin
                inc(NowPos,5);
              end;
            end;
            end else begin // ADPCM
            if (Cmd[1]=$80) or (Cmd[1]=$81) then begin
              inc(NowPos);
              end else begin
              inc(NowPos,5);
            end;
          end;
        end;
        $e9: begin // Set LFO Delay
          inc(NowPos);
        end;
        $e8: begin // Set Expanded PCM8 Mode
        end;
        $e7: begin // Start Fadeout
          case Cmd[1] of
            $00: begin end;
            $01: begin
              MDX.FadeoutFlag:=True;
              // Cmd[2] of FadeoutSpeed not use.
              inc(NowPos,2);
            end;
            else begin
              Enabled:=False;
            end;
          end;
        end;
        $e6: begin // Extend Command mxdrv16x system
          Enabled:=False;
        end;

        else begin
          if $e0<=Cmd[0] then begin
            Enabled:=False;
          end;
        end;
      end;
    end;
  end;
end;

//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------

procedure TMXDRVmDLL.MMLCheckForSeek;
var
  Ch,ChCnt:byte;
  Processed:array[0..15] of boolean;
  Processing:boolean;
  LoopLimit:integer;
  procedure Process(Ch:integer);
  begin
    with MMLChannel[Ch] do begin
      if NowKeycode<>0 then begin
        if Portament<>0 then begin
          inc(NowPortament,Portament);
          if Ch<=7 then SetOPMNoteNumber_V211(Ch,NowKeycode);
        end;
        if (KeyoffMode=True) and (StopClock>=1) then begin
          dec(StopClock);
          if StopClock=0 then begin
            Portament:=0;
            NowPortament:=0;
            NowKeycode:=0;
            StopClock:=0;
          end;
        end;
      end;
      if RestClock>=1 then begin
        dec(RestClock);
      end;
      if RestClock<=0 then begin
        if NowDriverVersion=MXDRVDriverVersion210 then MMLAnalize_V210(Ch,False);
        if NowDriverVersion=MXDRVDriverVersion211 then MMLAnalize_V211(Ch,False);
      end;
    end;
  end;
begin
  ChCnt:=MDX.MaxChannel;

  for Ch:=0 to ChCnt do begin
    Processed[Ch]:=False;
    with MMLChannel[Ch] do begin
      SetSignalWaitFlag:=False;
    end;
  end;

  Processing:=True;
  LoopLimit:=$ff;

  while (Processing=True) do begin
    dec(LoopLimit);
    if LoopLimit=$00 then begin
      WriteDebugLog('同期コマンドで無限ループに入りました。強制中断されます。');
      for Ch:=0 to ChCnt do begin
        MMLChannel[Ch].Enabled:=False;
      end;
      exit;
    end;

    Processing:=False;
    for Ch:=0 to ChCnt do begin
      with MMLChannel[Ch] do begin
        if (Processed[Ch]=False) and (Enabled=True) and (SignalWaitFlag=True) then begin
          Process(Ch);
          Processing:=True;
          Processed[Ch]:=True;
          if SignalWaitFlag=False then Processed[Ch]:=False;
        end;
      end;
    end;
    for Ch:=0 to ChCnt do begin
      with MMLChannel[Ch] do begin
        if (SignalWaitFlag=False) and (SetSignalWaitFlag=True) then begin
          Processing:=True;
          Processed[Ch]:=False;
          SignalWaitFlag:=True;
        end;
      end;
    end;
  end;

  ProcessFadeout;
end;

procedure TMXDRVmDLL.MMLCheckForMesure;
var
  Ch,ChCnt:byte;
  Processed:array[0..15] of boolean;
  Processing:boolean;
  LoopLimit:integer;
  procedure Process(Ch:integer);
  begin
    with MMLChannel[Ch] do begin
      if RestClock>=1 then begin
        dec(RestClock);
      end;
      if RestClock<=0 then begin
        MMLAnalizeForMesure(Ch);
      end;
    end;
  end;
begin
  ChCnt:=MDX.MaxChannel;

  for Ch:=0 to ChCnt do begin
    Processed[Ch]:=False;
    with MMLChannel[Ch] do begin
      SetSignalWaitFlag:=False;
    end;
  end;

  Processing:=True;
  LoopLimit:=$ff;

  while (Processing=True) do begin
    dec(LoopLimit);
    if LoopLimit=$00 then begin
      WriteDebugLog('同期コマンドで無限ループに入りました。強制中断されます。');
      for Ch:=0 to ChCnt do begin
        MMLChannel[Ch].Enabled:=False;
      end;
      exit;
    end;

    Processing:=False;
    for Ch:=0 to ChCnt do begin
      with MMLChannel[Ch] do begin
        if (Processed[Ch]=False) and (Enabled=True) and (SignalWaitFlag=True) then begin
          Process(Ch);
          Processing:=True;
          Processed[Ch]:=True;
          if SignalWaitFlag=False then Processed[Ch]:=False;
        end;
      end;
    end;
    for Ch:=0 to ChCnt do begin
      with MMLChannel[Ch] do begin
        if (SignalWaitFlag=False) and (SetSignalWaitFlag=True) then begin
          Processing:=True;
          Processed[Ch]:=False;
          SignalWaitFlag:=True;
        end;
      end;
    end;
  end;

  ProcessFadeout;
end;

procedure TMXDRVmDLL.MMLMesure;
var
  Enabled:boolean;
begin
  Enabled:=True;
  X68Sound_TotalVolume(0);
  while Enabled=True do begin
    inc(PlayInfo.MesureClock);
    MMLCheckForMesure;
    MMLInsideTrap(True,2);
    if MDX.EndFlag=True then Enabled:=False;
    if PlayInfo.MesureClock>=99999 then Enabled:=False;
  end;
  X68Sound_TotalVolume(MDX.MasterVolume);
end;

procedure TMXDRVmDLL.MMLSeek(SeekClock:integer);
var
  Enabled:boolean;
  Ch:integer;
begin
  X68Sound_TotalVolume(0);
  if SeekClock<integer(PlayInfo.TotalClock) then begin
    MDXOPMRegisterInit;
    PlayInfo.fPlayTimems:=0;
    PlayInfo.TotalClock:=0;
  end;

  for Ch:=0 to MDX.MaxChannel do begin
    with MMLChannel[Ch] do begin
      Portament:=0;
      NowPortament:=0;
      StopClock:=0;
      Noteon:=False;
      if Ch<=7 then
        SetOPMNoteoff(Ch)
        else
        SetADPCMNoteoff(Ch);
      NowKeycode:=0;
      KeyoffMode:=True;
    end;
  end;

  Enabled:=True;
  while ((integer(PlayInfo.TotalClock)<SeekClock) and (Enabled=True)) do begin
    inc(PlayInfo.TotalClock);
    with PlayInfo do begin
      fPlayTimems:=fPlayTimems+(($ff-integer(MDX.Tempo)) shl (10-6))/TimerBModify;
    end;
    MMLCheckForSeek;
    MMLInsideTrap(True,2);
    if MDX.EndFlag=True then Enabled:=False;
  end;
  X68Sound_TotalVolume(MDX.MasterVolume);
end;

procedure TMXDRVmDLL.MMLInsideTrap(FadeoutEnabled:boolean;FadeoutCount:integer);
begin
  if FadeoutEnabled=True then begin
    if FadeoutCount<=MDX.LoopCount then begin
      MDX.FadeoutFlag:=True;
    end;
    end else begin
  end;
end;

procedure TMXDRVmDLL.SetMute(Ch:byte;MuteFlag:boolean);
begin
  with MMLChannel[Ch] do begin
    Mute:=MuteFlag;
    Noteon:=False;
    Portament:=0;
    NowPortament:=0;
    NowKeycode:=0;
    if Ch<=7 then
      SetOPMNoteoff(Ch)
      else
      SetADPCMNoteoff(Ch);
  end;
end;

procedure TMXDRVmDLL.Init(PCMRate:integer);
var
  cnt:integer;
  PDXNo:word;
  FreqCnt:integer;
begin
  for PDXNo:=0 to ADPCMCount-1 do begin
    with ADPCM[PDXNo] do begin
      Enabled:=False;
      ADPCMData:=nil;
      PCMData:=nil;
    end;
  end;

  if ppConvCalced=True then begin
    for FreqCnt:=1 to ppFreqMax-1 do begin
      ppConvPosTables[FreqCnt]:=nil;
      ppConvModTables[FreqCnt]:=nil;
    end;
    ppConvCalced:=False;
  end;

  NowPCMRate:=PCMRate;
  TransTempo:=0;

  ppConvCalced:=False;
  ppFreqTable[ppFreq_Var]:=0;
  ppFreqTable[ppFreq_3906]:=3906;
  ppFreqTable[ppFreq_5208]:=5208;
  ppFreqTable[ppFreq_7812]:=7812;
  ppFreqTable[ppFreq_10416]:=10416;
  ppFreqTable[ppFreq_15625]:=15625;
  ppFreqTable[ppFreq_16000]:=16000;
  ppFreqTable[ppFreq_22050]:=22050;
  ppFreqTable[ppFreq_24000]:=24000;
  ppFreqTable[ppFreq_32000]:=32000;
  ppFreqTable[ppFreq_44100]:=44100;
  ppFreqTable[ppFreq_48000]:=48000;

  ppVolumeTable[ 0]:=2;
  ppVolumeTable[ 1]:=3;
  ppVolumeTable[ 2]:=4;
  ppVolumeTable[ 3]:=5;
  ppVolumeTable[ 4]:=6;
  ppVolumeTable[ 5]:=8;
  ppVolumeTable[ 6]:=10;
  ppVolumeTable[ 7]:=12;
  ppVolumeTable[ 8]:=16;
  ppVolumeTable[ 9]:=20;
  ppVolumeTable[10]:=24;
  ppVolumeTable[11]:=32;
  ppVolumeTable[12]:=40;
  ppVolumeTable[13]:=48;
  ppVolumeTable[14]:=64;
  ppVolumeTable[15]:=80;

  PlayInfo.fPlayTimems:=0;
  PlayInfo.TotalClock:=0;
  PlayInfo.MesureClock:=0;

  // Keynote -> OPMreg Table
  ToneTable[$00]:=$00; ToneTable[$01]:=$01; ToneTable[$02]:=$02; ToneTable[$03]:=$04; ToneTable[$04]:=$05; ToneTable[$05]:=$06; ToneTable[$06]:=$08; ToneTable[$07]:=$09;
  ToneTable[$08]:=$0a; ToneTable[$09]:=$0c; ToneTable[$0a]:=$0d; ToneTable[$0b]:=$0e; ToneTable[$0c]:=$10; ToneTable[$0d]:=$11; ToneTable[$0e]:=$12; ToneTable[$0f]:=$14;
  ToneTable[$10]:=$15; ToneTable[$11]:=$16; ToneTable[$12]:=$18; ToneTable[$13]:=$19; ToneTable[$14]:=$1a; ToneTable[$15]:=$1c; ToneTable[$16]:=$1d; ToneTable[$17]:=$1e;
  ToneTable[$18]:=$20; ToneTable[$19]:=$21; ToneTable[$1a]:=$22; ToneTable[$1b]:=$24; ToneTable[$1c]:=$25; ToneTable[$1d]:=$26; ToneTable[$1e]:=$28; ToneTable[$1f]:=$29;
  ToneTable[$20]:=$2a; ToneTable[$21]:=$2c; ToneTable[$22]:=$2d; ToneTable[$23]:=$2e; ToneTable[$24]:=$30; ToneTable[$25]:=$31; ToneTable[$26]:=$32; ToneTable[$27]:=$34;
  ToneTable[$28]:=$35; ToneTable[$29]:=$36; ToneTable[$2a]:=$38; ToneTable[$2b]:=$39; ToneTable[$2c]:=$3a; ToneTable[$2d]:=$3c; ToneTable[$2e]:=$3d; ToneTable[$2f]:=$3e;
  ToneTable[$30]:=$40; ToneTable[$31]:=$41; ToneTable[$32]:=$42; ToneTable[$33]:=$44; ToneTable[$34]:=$45; ToneTable[$35]:=$46; ToneTable[$36]:=$48; ToneTable[$37]:=$49;
  ToneTable[$38]:=$4a; ToneTable[$39]:=$4c; ToneTable[$3a]:=$4d; ToneTable[$3b]:=$4e; ToneTable[$3c]:=$50; ToneTable[$3d]:=$51; ToneTable[$3e]:=$52; ToneTable[$3f]:=$54;
  ToneTable[$40]:=$55; ToneTable[$41]:=$56; ToneTable[$42]:=$58; ToneTable[$43]:=$59; ToneTable[$44]:=$5a; ToneTable[$45]:=$5c; ToneTable[$46]:=$5d; ToneTable[$47]:=$5e;
  ToneTable[$48]:=$60; ToneTable[$49]:=$61; ToneTable[$4a]:=$62; ToneTable[$4b]:=$64; ToneTable[$4c]:=$65; ToneTable[$4d]:=$66; ToneTable[$4e]:=$68; ToneTable[$4f]:=$69;
  ToneTable[$50]:=$6a; ToneTable[$51]:=$6c; ToneTable[$52]:=$6d; ToneTable[$53]:=$6e; ToneTable[$54]:=$70; ToneTable[$55]:=$71; ToneTable[$56]:=$72; ToneTable[$57]:=$74;
  ToneTable[$58]:=$75; ToneTable[$59]:=$76; ToneTable[$5a]:=$78; ToneTable[$5b]:=$79; ToneTable[$5c]:=$7a; ToneTable[$5d]:=$7c; ToneTable[$5e]:=$7d; ToneTable[$5f]:=$7e;

  // SlotMask 3=C2 2=C1 1=M2 0=M1
  SlottoTL[ 0,3]:=False; SlottoTL[ 0,2]:=False; SlottoTL[ 0,1]:=False; SlottoTL[ 0,0]:=False;
  SlottoTL[ 1,3]:=False; SlottoTL[ 1,2]:=False; SlottoTL[ 1,1]:=False; SlottoTL[ 1,0]:=True;
  SlottoTL[ 2,3]:=False; SlottoTL[ 2,2]:=False; SlottoTL[ 2,1]:=True;  SlottoTL[ 2,0]:=False;
  SlottoTL[ 3,3]:=False; SlottoTL[ 3,2]:=False; SlottoTL[ 3,1]:=True;  SlottoTL[ 3,0]:=True;
  SlottoTL[ 4,3]:=False; SlottoTL[ 4,2]:=True;  SlottoTL[ 4,1]:=False; SlottoTL[ 4,0]:=False;
  SlottoTL[ 5,3]:=False; SlottoTL[ 5,2]:=True;  SlottoTL[ 5,1]:=False; SlottoTL[ 5,0]:=True;
  SlottoTL[ 6,3]:=False; SlottoTL[ 6,2]:=True;  SlottoTL[ 6,1]:=True;  SlottoTL[ 6,0]:=False;
  SlottoTL[ 7,3]:=False; SlottoTL[ 7,2]:=True;  SlottoTL[ 7,1]:=True;  SlottoTL[ 7,0]:=True;
  SlottoTL[ 8,3]:=True;  SlottoTL[ 8,2]:=False; SlottoTL[ 8,1]:=False; SlottoTL[ 8,0]:=False;
  SlottoTL[ 9,3]:=True;  SlottoTL[ 9,2]:=False; SlottoTL[ 9,1]:=False; SlottoTL[ 9,0]:=True;
  SlottoTL[10,3]:=True;  SlottoTL[10,2]:=False; SlottoTL[10,1]:=True;  SlottoTL[10,0]:=False;
  SlottoTL[11,3]:=True;  SlottoTL[11,2]:=False; SlottoTL[11,1]:=True;  SlottoTL[11,0]:=True;
  SlottoTL[12,3]:=True;  SlottoTL[12,2]:=True;  SlottoTL[12,1]:=False; SlottoTL[12,0]:=False;
  SlottoTL[13,3]:=True;  SlottoTL[13,2]:=True;  SlottoTL[13,1]:=False; SlottoTL[13,0]:=True;
  SlottoTL[14,3]:=True;  SlottoTL[14,2]:=True;  SlottoTL[14,1]:=True;  SlottoTL[14,0]:=False;
  SlottoTL[15,3]:=True;  SlottoTL[15,2]:=True;  SlottoTL[15,1]:=True;  SlottoTL[15,0]:=True;

  CarrierSlot[0]:=$08; CarrierSlot[1]:=$08; CarrierSlot[2]:=$08; CarrierSlot[3]:=$08;
  CarrierSlot[4]:=$0c; CarrierSlot[5]:=$0e; CarrierSlot[6]:=$0e; CarrierSlot[7]:=$0f;

  OPMVolTbl[ 0]:=$2a; OPMVolTbl[ 1]:=$28; OPMVolTbl[ 2]:=$25; OPMVolTbl[ 3]:=$22;
  OPMVolTbl[ 4]:=$20; OPMVolTbl[ 5]:=$1d; OPMVolTbl[ 6]:=$1a; OPMVolTbl[ 7]:=$18;
  OPMVolTbl[ 8]:=$15; OPMVolTbl[ 9]:=$12; OPMVolTbl[10]:=$10; OPMVolTbl[11]:=$0d;
  OPMVolTbl[12]:=$0a; OPMVolTbl[13]:=$08; OPMVolTbl[14]:=$05; OPMVolTbl[15]:=$02;

  for cnt:=0 to 15 do
    OPMVolTbl[cnt]:=127-OPMVolTbl[cnt];

  for cnt:=0 to $7f do
    PCMVolTbl[cnt]:=$0;

  PCMVolTbl[$00]:=$f; PCMVolTbl[$01]:=$f; PCMVolTbl[$02]:=$f; PCMVolTbl[$03]:=$e; PCMVolTbl[$04]:=$e; PCMVolTbl[$05]:=$e; PCMVolTbl[$06]:=$d; PCMVolTbl[$07]:=$d;
  PCMVolTbl[$08]:=$d; PCMVolTbl[$09]:=$c; PCMVolTbl[$0a]:=$c; PCMVolTbl[$0b]:=$b; PCMVolTbl[$0c]:=$b; PCMVolTbl[$0d]:=$b; PCMVolTbl[$0e]:=$a; PCMVolTbl[$0f]:=$a;
  PCMVolTbl[$10]:=$a; PCMVolTbl[$11]:=$9; PCMVolTbl[$12]:=$9; PCMVolTbl[$13]:=$8; PCMVolTbl[$14]:=$8; PCMVolTbl[$15]:=$8; PCMVolTbl[$16]:=$7; PCMVolTbl[$17]:=$7;
  PCMVolTbl[$18]:=$7; PCMVolTbl[$19]:=$6; PCMVolTbl[$1a]:=$6; PCMVolTbl[$1b]:=$5; PCMVolTbl[$1c]:=$5; PCMVolTbl[$1d]:=$5; PCMVolTbl[$1e]:=$4; PCMVolTbl[$1f]:=$4;
  PCMVolTbl[$20]:=$4; PCMVolTbl[$21]:=$3; PCMVolTbl[$22]:=$3; PCMVolTbl[$23]:=$2; PCMVolTbl[$24]:=$2; PCMVolTbl[$25]:=$2; PCMVolTbl[$26]:=$1; PCMVolTbl[$27]:=$1;
  PCMVolTbl[$28]:=$1; PCMVolTbl[$29]:=$0;
end;

procedure TMXDRVmDLL.OPMVoiceInit;
var
  no:integer;
begin
  for no:=0 to $ff do begin
    OPMVoice[no].Enabled:=False;
  end;

  with OPMVoice[$00] do begin
    Enabled:=False; Sync:=True; AF:=$3A; Slot:=$0F;
    Part[0,0]:=$71; Part[1,0]:=$33; Part[2,0]:=$0C; Part[3,0]:=$01;
    Part[0,1]:=$25; Part[1,1]:=$23; Part[2,1]:=$2F; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$1F; Part[2,2]:=$00; Part[3,2]:=$CF;
    Part[0,3]:=$05; Part[1,3]:=$05; Part[2,3]:=$05; Part[3,3]:=$04;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$03; Part[3,4]:=$00;
    Part[0,5]:=$16; Part[1,5]:=$16; Part[2,5]:=$16; Part[3,5]:=$00;
  end;

  with OPMVoice[$01] do begin
    Enabled:=False; Sync:=True; AF:=$34; Slot:=$0F;
    Part[0,0]:=$37; Part[1,0]:=$77; Part[2,0]:=$37; Part[3,0]:=$77;
    Part[0,1]:=$1E; Part[1,1]:=$28; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$1F; Part[2,2]:=$1F; Part[3,2]:=$1F;
    Part[0,3]:=$0A; Part[1,3]:=$0A; Part[2,3]:=$0B; Part[3,3]:=$0B;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$09; Part[3,4]:=$09;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$A7; Part[3,5]:=$A7;
  end;

  with OPMVoice[$02] do begin
    Enabled:=False; Sync:=True; AF:=$3C; Slot:=$0F;
    Part[0,0]:=$0F; Part[1,0]:=$01; Part[2,0]:=$01; Part[3,0]:=$01;
    Part[0,1]:=$35; Part[1,1]:=$25; Part[2,1]:=$0A; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$1F; Part[2,2]:=$1F; Part[3,2]:=$1F;
    Part[0,3]:=$0F; Part[1,3]:=$06; Part[2,3]:=$0C; Part[3,3]:=$0C;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$05; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$28; Part[3,5]:=$18;
  end;

  with OPMVoice[$03] do begin
    Enabled:=False; Sync:=True; AF:=$3A; Slot:=$0F;
    Part[0,0]:=$31; Part[1,0]:=$61; Part[2,0]:=$7F; Part[3,0]:=$0A;
    Part[0,1]:=$23; Part[1,1]:=$1B; Part[2,1]:=$25; Part[3,1]:=$00;
    Part[0,2]:=$00; Part[1,2]:=$00; Part[2,2]:=$DB; Part[3,2]:=$00;
    Part[0,3]:=$04; Part[1,3]:=$03; Part[2,3]:=$08; Part[3,3]:=$09;
    Part[0,4]:=$03; Part[1,4]:=$00; Part[2,4]:=$01; Part[3,4]:=$00;
    Part[0,5]:=$19; Part[1,5]:=$00; Part[2,5]:=$09; Part[3,5]:=$00;
  end;

  with OPMVoice[$04] do begin
    Enabled:=False; Sync:=True; AF:=$3D; Slot:=$0F;
    Part[0,0]:=$2E; Part[1,0]:=$7C; Part[2,0]:=$74; Part[3,0]:=$39;
    Part[0,1]:=$32; Part[1,1]:=$00; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$5F; Part[1,2]:=$5F; Part[2,2]:=$5F; Part[3,2]:=$5F;
    Part[0,3]:=$0A; Part[1,3]:=$0A; Part[2,3]:=$0A; Part[3,3]:=$0A;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$00; Part[3,5]:=$00;
  end;

  with OPMVoice[$05] do begin
    Enabled:=False; Sync:=True; AF:=$32; Slot:=$0F;
    Part[0,0]:=$73; Part[1,0]:=$71; Part[2,0]:=$4C; Part[3,0]:=$41;
    Part[0,1]:=$19; Part[1,1]:=$24; Part[2,1]:=$23; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$1F; Part[2,2]:=$1F; Part[3,2]:=$00;
    Part[0,3]:=$00; Part[1,3]:=$00; Part[2,3]:=$00; Part[3,3]:=$06;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$07; Part[1,5]:=$07; Part[2,5]:=$07; Part[3,5]:=$00;
  end;

  with OPMVoice[$06] do begin
    Enabled:=False; Sync:=True; AF:=$21; Slot:=$0F;
    Part[0,0]:=$12; Part[1,0]:=$43; Part[2,0]:=$73; Part[3,0]:=$21;
    Part[0,1]:=$2A; Part[1,1]:=$23; Part[2,1]:=$25; Part[3,1]:=$00;
    Part[0,2]:=$DC; Part[1,2]:=$DF; Part[2,2]:=$5F; Part[3,2]:=$00;
    Part[0,3]:=$05; Part[1,3]:=$03; Part[2,3]:=$07; Part[3,3]:=$02;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$04; Part[3,4]:=$01;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$23; Part[3,5]:=$14;
  end;

  with OPMVoice[$07] do begin
    Enabled:=False; Sync:=True; AF:=$3A; Slot:=$0F;
    Part[0,0]:=$3F; Part[1,0]:=$73; Part[2,0]:=$7A; Part[3,0]:=$31;
    Part[0,1]:=$23; Part[1,1]:=$28; Part[2,1]:=$28; Part[3,1]:=$00;
    Part[0,2]:=$00; Part[1,2]:=$54; Part[2,2]:=$5F; Part[3,2]:=$17;
    Part[0,3]:=$0D; Part[1,3]:=$0A; Part[2,3]:=$14; Part[3,3]:=$05;
    Part[0,4]:=$00; Part[1,4]:=$01; Part[2,4]:=$05; Part[3,4]:=$01;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$46; Part[3,5]:=$00;
  end;

  with OPMVoice[$08] do begin
    Enabled:=False; Sync:=True; AF:=$3A; Slot:=$0F;
    Part[0,0]:=$70; Part[1,0]:=$20; Part[2,0]:=$54; Part[3,0]:=$30;
    Part[0,1]:=$1E; Part[1,1]:=$1E; Part[2,1]:=$32; Part[3,1]:=$00;
    Part[0,2]:=$5F; Part[1,2]:=$1F; Part[2,2]:=$5F; Part[3,2]:=$5F;
    Part[0,3]:=$0D; Part[1,3]:=$0B; Part[2,3]:=$0B; Part[3,3]:=$0B;
    Part[0,4]:=$0B; Part[1,4]:=$08; Part[2,4]:=$08; Part[3,4]:=$08;
    Part[0,5]:=$27; Part[1,5]:=$27; Part[2,5]:=$27; Part[3,5]:=$28;
  end;
  
  with OPMVoice[$09] do begin
    Enabled:=False; Sync:=True; AF:=$03; Slot:=$0F;
    Part[0,0]:=$66; Part[1,0]:=$40; Part[2,0]:=$40; Part[3,0]:=$31;
    Part[0,1]:=$2D; Part[1,1]:=$19; Part[2,1]:=$19; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$1F; Part[2,2]:=$1F; Part[3,2]:=$1C;
    Part[0,3]:=$12; Part[1,3]:=$0A; Part[2,3]:=$0A; Part[3,3]:=$08;
    Part[0,4]:=$01; Part[1,4]:=$04; Part[2,4]:=$00; Part[3,4]:=$06;
    Part[0,5]:=$AA; Part[1,5]:=$16; Part[2,5]:=$2A; Part[3,5]:=$18;
  end;
  
  with OPMVoice[$0A] do begin
    Enabled:=False; Sync:=True; AF:=$3A; Slot:=$0F;
    Part[0,0]:=$75; Part[1,0]:=$61; Part[2,0]:=$0F; Part[3,0]:=$31;
    Part[0,1]:=$1B; Part[1,1]:=$20; Part[2,1]:=$1E; Part[3,1]:=$00;
    Part[0,2]:=$58; Part[1,2]:=$1C; Part[2,2]:=$1A; Part[3,2]:=$00;
    Part[0,3]:=$0A; Part[1,3]:=$10; Part[2,3]:=$10; Part[3,3]:=$0B;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$56; Part[1,5]:=$36; Part[2,5]:=$B6; Part[3,5]:=$00;
  end;

  with OPMVoice[$0B] do begin
    Enabled:=False; Sync:=True; AF:=$01; Slot:=$0F;
    Part[0,0]:=$73; Part[1,0]:=$11; Part[2,0]:=$39; Part[3,0]:=$01;
    Part[0,1]:=$28; Part[1,1]:=$12; Part[2,1]:=$23; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$1C; Part[2,2]:=$5F; Part[3,2]:=$52;
    Part[0,3]:=$10; Part[1,3]:=$07; Part[2,3]:=$0B; Part[3,3]:=$01;
    Part[0,4]:=$04; Part[1,4]:=$00; Part[2,4]:=$01; Part[3,4]:=$00;
    Part[0,5]:=$16; Part[1,5]:=$00; Part[2,5]:=$16; Part[3,5]:=$00;
  end;

  with OPMVoice[$0C] do begin
    Enabled:=False; Sync:=True; AF:=$3A; Slot:=$0F;
    Part[0,0]:=$03; Part[1,0]:=$01; Part[2,0]:=$73; Part[3,0]:=$01;
    Part[0,1]:=$28; Part[1,1]:=$25; Part[2,1]:=$1A; Part[3,1]:=$00;
    Part[0,2]:=$18; Part[1,2]:=$5F; Part[2,2]:=$58; Part[3,2]:=$5F;
    Part[0,3]:=$12; Part[1,3]:=$04; Part[2,3]:=$10; Part[3,3]:=$0A;
    Part[0,4]:=$01; Part[1,4]:=$02; Part[2,4]:=$01; Part[3,4]:=$00;
    Part[0,5]:=$55; Part[1,5]:=$C5; Part[2,5]:=$55; Part[3,5]:=$00;
  end;

  with OPMVoice[$0D] do begin
    Enabled:=False; Sync:=True; AF:=$38; Slot:=$0F;
    Part[0,0]:=$73; Part[1,0]:=$71; Part[2,0]:=$14; Part[3,0]:=$41;
    Part[0,1]:=$1C; Part[1,1]:=$20; Part[2,1]:=$1F; Part[3,1]:=$00;
    Part[0,2]:=$DA; Part[1,2]:=$DC; Part[2,2]:=$DD; Part[3,2]:=$DD;
    Part[0,3]:=$08; Part[1,3]:=$04; Part[2,3]:=$04; Part[3,3]:=$09;
    Part[0,4]:=$05; Part[1,4]:=$02; Part[2,4]:=$05; Part[3,4]:=$03;
    Part[0,5]:=$23; Part[1,5]:=$23; Part[2,5]:=$13; Part[3,5]:=$14;
  end;

  with OPMVoice[$0E] do begin
    Enabled:=False; Sync:=True; AF:=$3E; Slot:=$0F;
    Part[0,0]:=$38; Part[1,0]:=$11; Part[2,0]:=$72; Part[3,0]:=$26;
    Part[0,1]:=$28; Part[1,1]:=$00; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$14; Part[2,2]:=$14; Part[3,2]:=$14;
    Part[0,3]:=$14; Part[1,3]:=$02; Part[2,3]:=$02; Part[3,3]:=$02;
    Part[0,4]:=$00; Part[1,4]:=$01; Part[2,4]:=$01; Part[3,4]:=$01;
    Part[0,5]:=$0A; Part[1,5]:=$3A; Part[2,5]:=$3A; Part[3,5]:=$3A;
  end;

  with OPMVoice[$0F] do begin
    Enabled:=False; Sync:=True; AF:=$3F; Slot:=$0F;
    Part[0,0]:=$38; Part[1,0]:=$01; Part[2,0]:=$73; Part[3,0]:=$62;
    Part[0,1]:=$17; Part[1,1]:=$00; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$13; Part[2,2]:=$13; Part[3,2]:=$13;
    Part[0,3]:=$00; Part[1,3]:=$00; Part[2,3]:=$00; Part[3,3]:=$00;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$0A; Part[1,5]:=$0A; Part[2,5]:=$0A; Part[3,5]:=$0A;
  end;

  with OPMVoice[$10] do begin
    Enabled:=False; Sync:=True; AF:=$27; Slot:=$0F;
    Part[0,0]:=$37; Part[1,0]:=$03; Part[2,0]:=$03; Part[3,0]:=$72;
    Part[0,1]:=$06; Part[1,1]:=$02; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$1F; Part[2,2]:=$1F; Part[3,2]:=$1F;
    Part[0,3]:=$14; Part[1,3]:=$00; Part[2,3]:=$00; Part[3,3]:=$00;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$FF; Part[1,5]:=$0F; Part[2,5]:=$0F; Part[3,5]:=$0F;
  end;

  with OPMVoice[$11] do begin
    Enabled:=False; Sync:=True; AF:=$38; Slot:=$0F;
    Part[0,0]:=$36; Part[1,0]:=$71; Part[2,0]:=$37; Part[3,0]:=$72;
    Part[0,1]:=$27; Part[1,1]:=$26; Part[2,1]:=$26; Part[3,1]:=$00;
    Part[0,2]:=$5F; Part[1,2]:=$53; Part[2,2]:=$5F; Part[3,2]:=$50;
    Part[0,3]:=$00; Part[1,3]:=$02; Part[2,3]:=$03; Part[3,3]:=$00;
    Part[0,4]:=$00; Part[1,4]:=$01; Part[2,4]:=$01; Part[3,4]:=$00;
    Part[0,5]:=$08; Part[1,5]:=$18; Part[2,5]:=$18; Part[3,5]:=$09;
  end;

  with OPMVoice[$12] do begin
    Enabled:=False; Sync:=True; AF:=$3A; Slot:=$0F;
    Part[0,0]:=$01; Part[1,0]:=$01; Part[2,0]:=$75; Part[3,0]:=$41;
    Part[0,1]:=$21; Part[1,1]:=$30; Part[2,1]:=$1E; Part[3,1]:=$00;
    Part[0,2]:=$54; Part[1,2]:=$5C; Part[2,2]:=$59; Part[3,2]:=$4C;
    Part[0,3]:=$02; Part[1,3]:=$03; Part[2,3]:=$06; Part[3,3]:=$04;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$17; Part[1,5]:=$17; Part[2,5]:=$37; Part[3,5]:=$07;
  end;

  with OPMVoice[$13] do begin
    Enabled:=False; Sync:=True; AF:=$39; Slot:=$0F;
    Part[0,0]:=$7F; Part[1,0]:=$71; Part[2,0]:=$76; Part[3,0]:=$31;
    Part[0,1]:=$0A; Part[1,1]:=$1B; Part[2,1]:=$20; Part[3,1]:=$00;
    Part[0,2]:=$52; Part[1,2]:=$00; Part[2,2]:=$5F; Part[3,2]:=$4C;
    Part[0,3]:=$14; Part[1,3]:=$00; Part[2,3]:=$0C; Part[3,3]:=$00;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$FF; Part[1,5]:=$00; Part[2,5]:=$00; Part[3,5]:=$1A;
  end;

  with OPMVoice[$14] do begin
    Enabled:=False; Sync:=True; AF:=$3A; Slot:=$0F;
    Part[0,0]:=$20; Part[1,0]:=$31; Part[2,0]:=$32; Part[3,0]:=$41;
    Part[0,1]:=$1E; Part[1,1]:=$28; Part[2,1]:=$1E; Part[3,1]:=$00;
    Part[0,2]:=$DE; Part[1,2]:=$5E; Part[2,2]:=$DF; Part[3,2]:=$08;
    Part[0,3]:=$01; Part[1,3]:=$01; Part[2,3]:=$01; Part[3,3]:=$02;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$16; Part[1,5]:=$16; Part[2,5]:=$16; Part[3,5]:=$07;
  end;

  with OPMVoice[$15] do begin
    Enabled:=False; Sync:=True; AF:=$3D; Slot:=$0F;
    Part[0,0]:=$00; Part[1,0]:=$01; Part[2,0]:=$01; Part[3,0]:=$01;
    Part[0,1]:=$1F; Part[1,1]:=$00; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$0A; Part[2,2]:=$0A; Part[3,2]:=$0A;
    Part[0,3]:=$00; Part[1,3]:=$00; Part[2,3]:=$00; Part[3,3]:=$00;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$07; Part[1,5]:=$07; Part[2,5]:=$07; Part[3,5]:=$07;
  end;

  with OPMVoice[$16] do begin
    Enabled:=False; Sync:=True; AF:=$3C; Slot:=$0F;
    Part[0,0]:=$71; Part[1,0]:=$31; Part[2,0]:=$71; Part[3,0]:=$31;
    Part[0,1]:=$18; Part[1,1]:=$20; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$5F; Part[2,2]:=$52; Part[3,2]:=$5F;
    Part[0,3]:=$16; Part[1,3]:=$0C; Part[2,3]:=$0F; Part[3,3]:=$0F;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$08; Part[3,4]:=$08;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$00; Part[3,5]:=$00;
  end;

  with OPMVoice[$17] do begin
    Enabled:=False; Sync:=True; AF:=$17; Slot:=$0F;
    Part[0,0]:=$32; Part[1,0]:=$72; Part[2,0]:=$33; Part[3,0]:=$31;
    Part[0,1]:=$00; Part[1,1]:=$00; Part[2,1]:=$04; Part[3,1]:=$0A;
    Part[0,2]:=$0C; Part[1,2]:=$0C; Part[2,2]:=$0C; Part[3,2]:=$12;
    Part[0,3]:=$00; Part[1,3]:=$00; Part[2,3]:=$00; Part[3,3]:=$00;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$07; Part[1,5]:=$07; Part[2,5]:=$07; Part[3,5]:=$07;
  end;

  with OPMVoice[$18] do begin
    Enabled:=False; Sync:=True; AF:=$29; Slot:=$0F;
    Part[0,0]:=$3A; Part[1,0]:=$71; Part[2,0]:=$77; Part[3,0]:=$31;
    Part[0,1]:=$42; Part[1,1]:=$2D; Part[2,1]:=$34; Part[3,1]:=$00;
    Part[0,2]:=$13; Part[1,2]:=$0B; Part[2,2]:=$15; Part[3,2]:=$0E;
    Part[0,3]:=$12; Part[1,3]:=$03; Part[2,3]:=$0E; Part[3,3]:=$00;
    Part[0,4]:=$04; Part[1,4]:=$00; Part[2,4]:=$06; Part[3,4]:=$00;
    Part[0,5]:=$5A; Part[1,5]:=$00; Part[2,5]:=$6A; Part[3,5]:=$00;
  end;

  with OPMVoice[$19] do begin
    Enabled:=False; Sync:=True; AF:=$24; Slot:=$0F;
    Part[0,0]:=$7F; Part[1,0]:=$3F; Part[2,0]:=$72; Part[3,0]:=$32;
    Part[0,1]:=$24; Part[1,1]:=$25; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$54; Part[1,2]:=$D4; Part[2,2]:=$0A; Part[3,2]:=$0A;
    Part[0,3]:=$02; Part[1,3]:=$02; Part[2,3]:=$07; Part[3,3]:=$07;
    Part[0,4]:=$01; Part[1,4]:=$01; Part[2,4]:=$07; Part[3,4]:=$07;
    Part[0,5]:=$36; Part[1,5]:=$36; Part[2,5]:=$08; Part[3,5]:=$08;
  end;

  with OPMVoice[$1A] do begin
    Enabled:=False; Sync:=True; AF:=$07; Slot:=$0F;
    Part[0,0]:=$47; Part[1,0]:=$47; Part[2,0]:=$78; Part[3,0]:=$78;
    Part[0,1]:=$00; Part[1,1]:=$00; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$0F; Part[1,2]:=$0F; Part[2,2]:=$0D; Part[3,2]:=$0D;
    Part[0,3]:=$0C; Part[1,3]:=$0C; Part[2,3]:=$0C; Part[3,3]:=$0C;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$09; Part[1,5]:=$09; Part[2,5]:=$09; Part[3,5]:=$09;
  end;

  with OPMVoice[$1B] do begin
    Enabled:=False; Sync:=True; AF:=$3C; Slot:=$0F;
    Part[0,0]:=$02; Part[1,0]:=$0A; Part[2,0]:=$02; Part[3,0]:=$02;
    Part[0,1]:=$28; Part[1,1]:=$3C; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$52; Part[1,2]:=$52; Part[2,2]:=$13; Part[3,2]:=$13;
    Part[0,3]:=$0A; Part[1,3]:=$0A; Part[2,3]:=$0B; Part[3,3]:=$0B;
    Part[0,4]:=$01; Part[1,4]:=$01; Part[2,4]:=$03; Part[3,4]:=$03;
    Part[0,5]:=$38; Part[1,5]:=$58; Part[2,5]:=$29; Part[3,5]:=$29;
  end;

  with OPMVoice[$1C] do begin
    Enabled:=False; Sync:=True; AF:=$3B; Slot:=$0F;
    Part[0,0]:=$7C; Part[1,0]:=$34; Part[2,0]:=$08; Part[3,0]:=$04;
    Part[0,1]:=$2A; Part[1,1]:=$30; Part[2,1]:=$33; Part[3,1]:=$00;
    Part[0,2]:=$DC; Part[1,2]:=$CE; Part[2,2]:=$4B; Part[3,2]:=$00;
    Part[0,3]:=$05; Part[1,3]:=$02; Part[2,3]:=$07; Part[3,3]:=$10;
    Part[0,4]:=$03; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$26; Part[2,5]:=$00; Part[3,5]:=$17;
  end;

  with OPMVoice[$1D] do begin
    Enabled:=False; Sync:=True; AF:=$3A; Slot:=$0F;
    Part[0,0]:=$01; Part[1,0]:=$02; Part[2,0]:=$09; Part[3,0]:=$04;
    Part[0,1]:=$23; Part[1,1]:=$28; Part[2,1]:=$23; Part[3,1]:=$00;
    Part[0,2]:=$D9; Part[1,2]:=$59; Part[2,2]:=$DC; Part[3,2]:=$51;
    Part[0,3]:=$0B; Part[1,3]:=$10; Part[2,3]:=$0C; Part[3,3]:=$0A;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$0C; Part[3,4]:=$00;
    Part[0,5]:=$1B; Part[1,5]:=$1B; Part[2,5]:=$5B; Part[3,5]:=$1B;
  end;
  
  with OPMVoice[$1E] do begin
    Enabled:=False; Sync:=True; AF:=$3A; Slot:=$0F;
    Part[0,0]:=$02; Part[1,0]:=$01; Part[2,0]:=$09; Part[3,0]:=$01;
    Part[0,1]:=$23; Part[1,1]:=$28; Part[2,1]:=$1E; Part[3,1]:=$00;
    Part[0,2]:=$53; Part[1,2]:=$5D; Part[2,2]:=$1C; Part[3,2]:=$11;
    Part[0,3]:=$02; Part[1,3]:=$14; Part[2,3]:=$12; Part[3,3]:=$0F;
    Part[0,4]:=$02; Part[1,4]:=$01; Part[2,4]:=$03; Part[3,4]:=$00;
    Part[0,5]:=$18; Part[1,5]:=$18; Part[2,5]:=$48; Part[3,5]:=$09;
  end;

  with OPMVoice[$1F] do begin
    Enabled:=False; Sync:=True; AF:=$2C; Slot:=$0F;
    Part[0,0]:=$32; Part[1,0]:=$72; Part[2,0]:=$34; Part[3,0]:=$7A;
    Part[0,1]:=$28; Part[1,1]:=$1E; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$12; Part[1,2]:=$13; Part[2,2]:=$54; Part[3,2]:=$14;
    Part[0,3]:=$00; Part[1,3]:=$0E; Part[2,3]:=$00; Part[3,3]:=$00;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$0A; Part[1,5]:=$1A; Part[2,5]:=$0A; Part[3,5]:=$0A;
  end;

  with OPMVoice[$20] do begin
    Enabled:=False; Sync:=True; AF:=$3A; Slot:=$0F;
    Part[0,0]:=$01; Part[1,0]:=$01; Part[2,0]:=$0B; Part[3,0]:=$72;
    Part[0,1]:=$20; Part[1,1]:=$28; Part[2,1]:=$2D; Part[3,1]:=$00;
    Part[0,2]:=$12; Part[1,2]:=$12; Part[2,2]:=$12; Part[3,2]:=$0E;
    Part[0,3]:=$00; Part[1,3]:=$00; Part[2,3]:=$00; Part[3,3]:=$08;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$06; Part[1,5]:=$06; Part[2,5]:=$06; Part[3,5]:=$18;
  end;

  with OPMVoice[$21] do begin
    Enabled:=False; Sync:=True; AF:=$3A; Slot:=$0F;
    Part[0,0]:=$61; Part[1,0]:=$31; Part[2,0]:=$27; Part[3,0]:=$71;
    Part[0,1]:=$19; Part[1,1]:=$28; Part[2,1]:=$23; Part[3,1]:=$00;
    Part[0,2]:=$00; Part[1,2]:=$00; Part[2,2]:=$00; Part[3,2]:=$53;
    Part[0,3]:=$0E; Part[1,3]:=$0E; Part[2,3]:=$0E; Part[3,3]:=$03;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$19; Part[1,5]:=$19; Part[2,5]:=$00; Part[3,5]:=$0A;
  end;

  with OPMVoice[$22] do begin
    Enabled:=False; Sync:=True; AF:=$3A; Slot:=$0F;
    Part[0,0]:=$41; Part[1,0]:=$41; Part[2,0]:=$48; Part[3,0]:=$41;
    Part[0,1]:=$21; Part[1,1]:=$28; Part[2,1]:=$28; Part[3,1]:=$00;
    Part[0,2]:=$0D; Part[1,2]:=$0C; Part[2,2]:=$5F; Part[3,2]:=$0E;
    Part[0,3]:=$09; Part[1,3]:=$0B; Part[2,3]:=$11; Part[3,3]:=$00;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$38; Part[1,5]:=$18; Part[2,5]:=$C8; Part[3,5]:=$0A;
  end;

  with OPMVoice[$23] do begin
    Enabled:=False; Sync:=True; AF:=$3A; Slot:=$0F;
    Part[0,0]:=$04; Part[1,0]:=$04; Part[2,0]:=$0C; Part[3,0]:=$04;
    Part[0,1]:=$1C; Part[1,1]:=$23; Part[2,1]:=$28; Part[3,1]:=$00;
    Part[0,2]:=$10; Part[1,2]:=$14; Part[2,2]:=$0E; Part[3,2]:=$10;
    Part[0,3]:=$0C; Part[1,3]:=$0E; Part[2,3]:=$0E; Part[3,3]:=$0E;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$08; Part[1,5]:=$7A; Part[2,5]:=$00; Part[3,5]:=$18;
  end;
  
  with OPMVoice[$24] do begin
    Enabled:=False; Sync:=True; AF:=$36; Slot:=$0F;
    Part[0,0]:=$10; Part[1,0]:=$71; Part[2,0]:=$31; Part[3,0]:=$30;
    Part[0,1]:=$15; Part[1,1]:=$00; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$4F; Part[1,2]:=$00; Part[2,2]:=$11; Part[3,2]:=$00;
    Part[0,3]:=$0A; Part[1,3]:=$02; Part[2,3]:=$02; Part[3,3]:=$02;
    Part[0,4]:=$01; Part[1,4]:=$12; Part[2,4]:=$01; Part[3,4]:=$01;
    Part[0,5]:=$65; Part[1,5]:=$5A; Part[2,5]:=$38; Part[3,5]:=$5A;
  end;

  with OPMVoice[$25] do begin
    Enabled:=False; Sync:=True; AF:=$3C; Slot:=$0F;
    Part[0,0]:=$71; Part[1,0]:=$41; Part[2,0]:=$71; Part[3,0]:=$41;
    Part[0,1]:=$20; Part[1,1]:=$13; Part[2,1]:=$00; Part[3,1]:=$05;
    Part[0,2]:=$52; Part[1,2]:=$4F; Part[2,2]:=$12; Part[3,2]:=$14;
    Part[0,3]:=$0C; Part[1,3]:=$0A; Part[2,3]:=$0A; Part[3,3]:=$02;
    Part[0,4]:=$01; Part[1,4]:=$01; Part[2,4]:=$01; Part[3,4]:=$01;
    Part[0,5]:=$2A; Part[1,5]:=$5A; Part[2,5]:=$3A; Part[3,5]:=$3A;
  end;

  with OPMVoice[$26] do begin
    Enabled:=False; Sync:=True; AF:=$3C; Slot:=$0F;
    Part[0,0]:=$71; Part[1,0]:=$31; Part[2,0]:=$72; Part[3,0]:=$32;
    Part[0,1]:=$18; Part[1,1]:=$12; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$10; Part[1,2]:=$10; Part[2,2]:=$10; Part[3,2]:=$10;
    Part[0,3]:=$0F; Part[1,3]:=$0F; Part[2,3]:=$00; Part[3,3]:=$00;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$19; Part[1,5]:=$19; Part[2,5]:=$1A; Part[3,5]:=$0A;
  end;

  with OPMVoice[$27] do begin
    Enabled:=False; Sync:=True; AF:=$38; Slot:=$0F;
    Part[0,0]:=$39; Part[1,0]:=$31; Part[2,0]:=$77; Part[3,0]:=$73;
    Part[0,1]:=$26; Part[1,1]:=$25; Part[2,1]:=$26; Part[3,1]:=$00;
    Part[0,2]:=$12; Part[1,2]:=$0F; Part[2,2]:=$12; Part[3,2]:=$0F;
    Part[0,3]:=$00; Part[1,3]:=$05; Part[2,3]:=$00; Part[3,3]:=$08;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$08; Part[1,5]:=$18; Part[2,5]:=$08; Part[3,5]:=$29;
  end;

  with OPMVoice[$28] do begin
    Enabled:=False; Sync:=True; AF:=$3B; Slot:=$0F;
    Part[0,0]:=$08; Part[1,0]:=$0A; Part[2,0]:=$04; Part[3,0]:=$08;
    Part[0,1]:=$0C; Part[1,1]:=$4D; Part[2,1]:=$4D; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$14; Part[2,2]:=$18; Part[3,2]:=$10;
    Part[0,3]:=$10; Part[1,3]:=$14; Part[2,3]:=$0A; Part[3,3]:=$05;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$3A; Part[2,5]:=$0A; Part[3,5]:=$7A;
  end;

  with OPMVoice[$29] do begin
    Enabled:=False; Sync:=True; AF:=$3B; Slot:=$0F;
    Part[0,0]:=$4D; Part[1,0]:=$74; Part[2,0]:=$44; Part[3,0]:=$42;
    Part[0,1]:=$37; Part[1,1]:=$2F; Part[2,1]:=$2F; Part[3,1]:=$00;
    Part[0,2]:=$11; Part[1,2]:=$0D; Part[2,2]:=$0F; Part[3,2]:=$10;
    Part[0,3]:=$11; Part[1,3]:=$14; Part[2,3]:=$12; Part[3,3]:=$1F;
    Part[0,4]:=$10; Part[1,4]:=$00; Part[2,4]:=$01; Part[3,4]:=$00;
    Part[0,5]:=$38; Part[1,5]:=$28; Part[2,5]:=$28; Part[3,5]:=$09;
  end;

  with OPMVoice[$2A] do begin
    Enabled:=False; Sync:=True; AF:=$02; Slot:=$0F;
    Part[0,0]:=$06; Part[1,0]:=$0A; Part[2,0]:=$0A; Part[3,0]:=$02;
    Part[0,1]:=$2F; Part[1,1]:=$2B; Part[2,1]:=$2B; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$1F; Part[2,2]:=$1F; Part[3,2]:=$14;
    Part[0,3]:=$00; Part[1,3]:=$00; Part[2,3]:=$00; Part[3,3]:=$08;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$0A; Part[1,5]:=$0A; Part[2,5]:=$0A; Part[3,5]:=$1A;
  end;

  with OPMVoice[$2B] do begin
    Enabled:=False; Sync:=True; AF:=$3B; Slot:=$0F;
    Part[0,0]:=$04; Part[1,0]:=$03; Part[2,0]:=$32; Part[3,0]:=$01;
    Part[0,1]:=$00; Part[1,1]:=$26; Part[2,1]:=$46; Part[3,1]:=$00;
    Part[0,2]:=$14; Part[1,2]:=$12; Part[2,2]:=$0E; Part[3,2]:=$0E;
    Part[0,3]:=$00; Part[1,3]:=$12; Part[2,3]:=$10; Part[3,3]:=$0C;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$0A; Part[1,5]:=$00; Part[2,5]:=$5A; Part[3,5]:=$2A;
  end;

  with OPMVoice[$2C] do begin
    Enabled:=False; Sync:=True; AF:=$3C; Slot:=$0F;
    Part[0,0]:=$0F; Part[1,0]:=$05; Part[2,0]:=$01; Part[3,0]:=$01;
    Part[0,1]:=$00; Part[1,1]:=$00; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$1F; Part[2,2]:=$1F; Part[3,2]:=$1F;
    Part[0,3]:=$19; Part[1,3]:=$19; Part[2,3]:=$12; Part[3,3]:=$11;
    Part[0,4]:=$05; Part[1,4]:=$00; Part[2,4]:=$12; Part[3,4]:=$0F;
    Part[0,5]:=$0F; Part[1,5]:=$FF; Part[2,5]:=$7C; Part[3,5]:=$00;
  end;

  with OPMVoice[$2D] do begin
    Enabled:=False; Sync:=True; AF:=$02; Slot:=$0F;
    Part[0,0]:=$0E; Part[1,0]:=$34; Part[2,0]:=$73; Part[3,0]:=$04;
    Part[0,1]:=$2B; Part[1,1]:=$0F; Part[2,1]:=$2F; Part[3,1]:=$00;
    Part[0,2]:=$1E; Part[1,2]:=$1E; Part[2,2]:=$1E; Part[3,2]:=$1E;
    Part[0,3]:=$10; Part[1,3]:=$14; Part[2,3]:=$0A; Part[3,3]:=$13;
    Part[0,4]:=$01; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$00; Part[3,5]:=$00;
  end;

  with OPMVoice[$2E] do begin
    Enabled:=False; Sync:=True; AF:=$00; Slot:=$0F;
    Part[0,0]:=$03; Part[1,0]:=$02; Part[2,0]:=$0C; Part[3,0]:=$02;
    Part[0,1]:=$1A; Part[1,1]:=$05; Part[2,1]:=$25; Part[3,1]:=$00;
    Part[0,2]:=$1E; Part[1,2]:=$1E; Part[2,2]:=$1E; Part[3,2]:=$1D;
    Part[0,3]:=$1A; Part[1,3]:=$10; Part[2,3]:=$1C; Part[3,3]:=$10;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$00; Part[3,5]:=$00;
  end;

  with OPMVoice[$2F] do begin
    Enabled:=False; Sync:=True; AF:=$3B; Slot:=$0F;
    Part[0,0]:=$0A; Part[1,0]:=$31; Part[2,0]:=$03; Part[3,0]:=$02;
    Part[0,1]:=$16; Part[1,1]:=$11; Part[2,1]:=$11; Part[3,1]:=$00;
    Part[0,2]:=$1C; Part[1,2]:=$DC; Part[2,2]:=$DC; Part[3,2]:=$5E;
    Part[0,3]:=$14; Part[1,3]:=$0F; Part[2,3]:=$13; Part[3,3]:=$0C;
    Part[0,4]:=$0C; Part[1,4]:=$0A; Part[2,4]:=$05; Part[3,4]:=$07;
    Part[0,5]:=$A7; Part[1,5]:=$57; Part[2,5]:=$A7; Part[3,5]:=$68;
  end;

  with OPMVoice[$30] do begin
    Enabled:=False; Sync:=True; AF:=$3A; Slot:=$0F;
    Part[0,0]:=$06; Part[1,0]:=$04; Part[2,0]:=$05; Part[3,0]:=$04;
    Part[0,1]:=$24; Part[1,1]:=$22; Part[2,1]:=$18; Part[3,1]:=$00;
    Part[0,2]:=$5C; Part[1,2]:=$1C; Part[2,2]:=$54; Part[3,2]:=$D0;
    Part[0,3]:=$0C; Part[1,3]:=$0A; Part[2,3]:=$0C; Part[3,3]:=$0C;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$08; Part[3,4]:=$08;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$26; Part[3,5]:=$27;
  end;

  with OPMVoice[$31] do begin
    Enabled:=False; Sync:=True; AF:=$3B; Slot:=$0F;
    Part[0,0]:=$0B; Part[1,0]:=$07; Part[2,0]:=$05; Part[3,0]:=$01;
    Part[0,1]:=$00; Part[1,1]:=$39; Part[2,1]:=$28; Part[3,1]:=$00;
    Part[0,2]:=$18; Part[1,2]:=$1A; Part[2,2]:=$1A; Part[3,2]:=$00;
    Part[0,3]:=$17; Part[1,3]:=$0A; Part[2,3]:=$0E; Part[3,3]:=$10;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$00; Part[3,5]:=$00;
  end;

  with OPMVoice[$32] do begin
    Enabled:=False; Sync:=True; AF:=$32; Slot:=$0F;
    Part[0,0]:=$37; Part[1,0]:=$3A; Part[2,0]:=$7B; Part[3,0]:=$77;
    Part[0,1]:=$1A; Part[1,1]:=$1D; Part[2,1]:=$20; Part[3,1]:=$00;
    Part[0,2]:=$5C; Part[1,2]:=$5A; Part[2,2]:=$18; Part[3,2]:=$00;
    Part[0,3]:=$0F; Part[1,3]:=$0B; Part[2,3]:=$10; Part[3,3]:=$07;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$00; Part[3,5]:=$00;
  end;

  with OPMVoice[$33] do begin
    Enabled:=False; Sync:=True; AF:=$03; Slot:=$0F;
    Part[0,0]:=$02; Part[1,0]:=$3C; Part[2,0]:=$7D; Part[3,0]:=$3F;
    Part[0,1]:=$33; Part[1,1]:=$43; Part[2,1]:=$1B; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$1F; Part[2,2]:=$1F; Part[3,2]:=$1F;
    Part[0,3]:=$06; Part[1,3]:=$08; Part[2,3]:=$00; Part[3,3]:=$0A;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$56; Part[2,5]:=$02; Part[3,5]:=$00;
  end;

  with OPMVoice[$34] do begin
    Enabled:=False; Sync:=True; AF:=$3B; Slot:=$0F;
    Part[0,0]:=$2F; Part[1,0]:=$37; Part[2,0]:=$0B; Part[3,0]:=$07;
    Part[0,1]:=$1B; Part[1,1]:=$2B; Part[2,1]:=$1B; Part[3,1]:=$00;
    Part[0,2]:=$1E; Part[1,2]:=$5C; Part[2,2]:=$5E; Part[3,2]:=$5A;
    Part[0,3]:=$14; Part[1,3]:=$0C; Part[2,3]:=$11; Part[3,3]:=$10;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$00; Part[3,5]:=$00;
  end;
  
  with OPMVoice[$35] do begin
    Enabled:=False; Sync:=True; AF:=$04; Slot:=$0F;
    Part[0,0]:=$37; Part[1,0]:=$77; Part[2,0]:=$72; Part[3,0]:=$32;
    Part[0,1]:=$23; Part[1,1]:=$23; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$1F; Part[2,2]:=$1F; Part[3,2]:=$1F;
    Part[0,3]:=$07; Part[1,3]:=$07; Part[2,3]:=$0A; Part[3,3]:=$0D;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$16; Part[1,5]:=$16; Part[2,5]:=$07; Part[3,5]:=$07;
  end;

  with OPMVoice[$36] do begin
    Enabled:=False; Sync:=True; AF:=$04; Slot:=$0F;
    Part[0,0]:=$73; Part[1,0]:=$31; Part[2,0]:=$71; Part[3,0]:=$34;
    Part[0,1]:=$1D; Part[1,1]:=$23; Part[2,1]:=$00; Part[3,1]:=$07;
    Part[0,2]:=$4D; Part[1,2]:=$00; Part[2,2]:=$00; Part[3,2]:=$00;
    Part[0,3]:=$0A; Part[1,3]:=$08; Part[2,3]:=$07; Part[3,3]:=$08;
    Part[0,4]:=$04; Part[1,4]:=$05; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$00; Part[3,5]:=$00;
  end;

  with OPMVoice[$37] do begin
    Enabled:=False; Sync:=True; AF:=$1C; Slot:=$0F;
    Part[0,0]:=$2E; Part[1,0]:=$0F; Part[2,0]:=$02; Part[3,0]:=$02;
    Part[0,1]:=$20; Part[1,1]:=$1B; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$1F; Part[2,2]:=$1F; Part[3,2]:=$1F;
    Part[0,3]:=$18; Part[1,3]:=$14; Part[2,3]:=$0F; Part[3,3]:=$0E;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$00; Part[3,5]:=$00;
  end;

  with OPMVoice[$38] do begin
    Enabled:=False; Sync:=True; AF:=$2C; Slot:=$0F;
    Part[0,0]:=$3C; Part[1,0]:=$74; Part[2,0]:=$34; Part[3,0]:=$71;
    Part[0,1]:=$32; Part[1,1]:=$39; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$58; Part[1,2]:=$5A; Part[2,2]:=$58; Part[3,2]:=$00;
    Part[0,3]:=$0E; Part[1,3]:=$0E; Part[2,3]:=$0A; Part[3,3]:=$08;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$00; Part[3,5]:=$00;
  end;
  
  with OPMVoice[$39] do begin
    Enabled:=False; Sync:=True; AF:=$2C; Slot:=$0F;
    Part[0,0]:=$34; Part[1,0]:=$76; Part[2,0]:=$30; Part[3,0]:=$72;
    Part[0,1]:=$2A; Part[1,1]:=$20; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$58; Part[1,2]:=$58; Part[2,2]:=$D8; Part[3,2]:=$00;
    Part[0,3]:=$11; Part[1,3]:=$14; Part[2,3]:=$04; Part[3,3]:=$0C;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$00; Part[3,5]:=$00;
  end;

  with OPMVoice[$3A] do begin
    Enabled:=False; Sync:=True; AF:=$3B; Slot:=$0F;
    Part[0,0]:=$09; Part[1,0]:=$0B; Part[2,0]:=$08; Part[3,0]:=$01;
    Part[0,1]:=$00; Part[1,1]:=$1B; Part[2,1]:=$1B; Part[3,1]:=$00;
    Part[0,2]:=$1D; Part[1,2]:=$1D; Part[2,2]:=$1D; Part[3,2]:=$1E;
    Part[0,3]:=$04; Part[1,3]:=$17; Part[2,3]:=$0F; Part[3,3]:=$14;
    Part[0,4]:=$03; Part[1,4]:=$00; Part[2,4]:=$03; Part[3,4]:=$15;
    Part[0,5]:=$3F; Part[1,5]:=$FF; Part[2,5]:=$7F; Part[3,5]:=$FF;
  end;

  with OPMVoice[$3B] do begin
    Enabled:=False; Sync:=True; AF:=$34; Slot:=$0F;
    Part[0,0]:=$07; Part[1,0]:=$75; Part[2,0]:=$09; Part[3,0]:=$07;
    Part[0,1]:=$07; Part[1,1]:=$13; Part[2,1]:=$0C; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$1F; Part[2,2]:=$1F; Part[3,2]:=$1F;
    Part[0,3]:=$01; Part[1,3]:=$16; Part[2,3]:=$0D; Part[3,3]:=$14;
    Part[0,4]:=$00; Part[1,4]:=$07; Part[2,4]:=$0F; Part[3,4]:=$14;
    Part[0,5]:=$C4; Part[1,5]:=$64; Part[2,5]:=$00; Part[3,5]:=$00;
  end;

  with OPMVoice[$3C] do begin
    Enabled:=False; Sync:=True; AF:=$2C; Slot:=$0F;
    Part[0,0]:=$75; Part[1,0]:=$72; Part[2,0]:=$07; Part[3,0]:=$0C;
    Part[0,1]:=$04; Part[1,1]:=$07; Part[2,1]:=$00; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$19; Part[2,2]:=$1F; Part[3,2]:=$1F;
    Part[0,3]:=$04; Part[1,3]:=$1C; Part[2,3]:=$1F; Part[3,3]:=$15;
    Part[0,4]:=$00; Part[1,4]:=$05; Part[2,4]:=$0A; Part[3,4]:=$0C;
    Part[0,5]:=$10; Part[1,5]:=$33; Part[2,5]:=$16; Part[3,5]:=$76;
  end;

  with OPMVoice[$3D] do begin
    Enabled:=False; Sync:=True; AF:=$1A; Slot:=$0F;
    Part[0,0]:=$12; Part[1,0]:=$00; Part[2,0]:=$04; Part[3,0]:=$31;
    Part[0,1]:=$11; Part[1,1]:=$19; Part[2,1]:=$0C; Part[3,1]:=$00;
    Part[0,2]:=$52; Part[1,2]:=$1F; Part[2,2]:=$14; Part[3,2]:=$00;
    Part[0,3]:=$01; Part[1,3]:=$13; Part[2,3]:=$01; Part[3,3]:=$02;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$01;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$00; Part[3,5]:=$3A;
  end;

  with OPMVoice[$3E] do begin
    Enabled:=False; Sync:=True; AF:=$1C; Slot:=$0F;
    Part[0,0]:=$38; Part[1,0]:=$78; Part[2,0]:=$34; Part[3,0]:=$74;
    Part[0,1]:=$07; Part[1,1]:=$0C; Part[2,1]:=$07; Part[3,1]:=$00;
    Part[0,2]:=$5F; Part[1,2]:=$5F; Part[2,2]:=$5F; Part[3,2]:=$5F;
    Part[0,3]:=$10; Part[1,3]:=$00; Part[2,3]:=$00; Part[3,3]:=$00;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$08; Part[2,5]:=$08; Part[3,5]:=$08;
  end;

  with OPMVoice[$3F] do begin
    Enabled:=False; Sync:=True; AF:=$04; Slot:=$0F;
    Part[0,0]:=$01; Part[1,0]:=$0E; Part[2,0]:=$01; Part[3,0]:=$77;
    Part[0,1]:=$7F; Part[1,1]:=$25; Part[2,1]:=$7F; Part[3,1]:=$00;
    Part[0,2]:=$00; Part[1,2]:=$1F; Part[2,2]:=$00; Part[3,2]:=$10;
    Part[0,3]:=$00; Part[1,3]:=$00; Part[2,3]:=$00; Part[3,3]:=$00;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$01; Part[2,5]:=$00; Part[3,5]:=$04;
  end;

  with OPMVoice[$40] do begin
    Enabled:=False; Sync:=True; AF:=$3A; Slot:=$0F;
    Part[0,0]:=$0D; Part[1,0]:=$07; Part[2,0]:=$05; Part[3,0]:=$02;
    Part[0,1]:=$11; Part[1,1]:=$1D; Part[2,1]:=$0A; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$1F; Part[2,2]:=$1F; Part[3,2]:=$0C;
    Part[0,3]:=$00; Part[1,3]:=$00; Part[2,3]:=$00; Part[3,3]:=$00;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$06; Part[1,5]:=$06; Part[2,5]:=$06; Part[3,5]:=$08;
  end;

  with OPMVoice[$41] do begin
    Enabled:=False; Sync:=True; AF:=$04; Slot:=$0F;
    Part[0,0]:=$01; Part[1,0]:=$04; Part[2,0]:=$0A; Part[3,0]:=$01;
    Part[0,1]:=$0F; Part[1,1]:=$2F; Part[2,1]:=$07; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$0C; Part[2,2]:=$14; Part[3,2]:=$10;
    Part[0,3]:=$00; Part[1,3]:=$00; Part[2,3]:=$00; Part[3,3]:=$00;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$0A; Part[1,5]:=$0A; Part[2,5]:=$0A; Part[3,5]:=$0A;
  end;

  with OPMVoice[$42] do begin
    Enabled:=False; Sync:=True; AF:=$06; Slot:=$0F;
    Part[0,0]:=$0C; Part[1,0]:=$03; Part[2,0]:=$04; Part[3,0]:=$02;
    Part[0,1]:=$19; Part[1,1]:=$00; Part[2,1]:=$07; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$14; Part[2,2]:=$14; Part[3,2]:=$14;
    Part[0,3]:=$00; Part[1,3]:=$0E; Part[2,3]:=$0E; Part[3,3]:=$0E;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$00; Part[3,5]:=$00;
  end;

  with OPMVoice[$43] do begin
    Enabled:=False; Sync:=True; AF:=$20; Slot:=$0F;
    Part[0,0]:=$08; Part[1,0]:=$03; Part[2,0]:=$03; Part[3,0]:=$01;
    Part[0,1]:=$0D; Part[1,1]:=$03; Part[2,1]:=$11; Part[3,1]:=$00;
    Part[0,2]:=$1F; Part[1,2]:=$1F; Part[2,2]:=$CA; Part[3,2]:=$D0;
    Part[0,3]:=$08; Part[1,3]:=$00; Part[2,3]:=$07; Part[3,3]:=$09;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$00; Part[1,5]:=$00; Part[2,5]:=$00; Part[3,5]:=$00;
  end;

  with OPMVoice[$FF] do begin
    Enabled:=False; Sync:=True; AF:=$39; Slot:=$0F;
    Part[0,0]:=$02; Part[1,0]:=$02; Part[2,0]:=$01; Part[3,0]:=$01;
    Part[0,1]:=$1A; Part[1,1]:=$22; Part[2,1]:=$34; Part[3,1]:=$05;
    Part[0,2]:=$1F; Part[1,2]:=$1F; Part[2,2]:=$1F; Part[3,2]:=$1F;
    Part[0,3]:=$00; Part[1,3]:=$00; Part[2,3]:=$00; Part[3,3]:=$00;
    Part[0,4]:=$00; Part[1,4]:=$00; Part[2,4]:=$00; Part[3,4]:=$00;
    Part[0,5]:=$0F; Part[1,5]:=$0F; Part[2,5]:=$0F; Part[3,5]:=$0F;
  end;
end;

procedure TMXDRVmDLL.CheckppAllChannel;
var
  cnt,ch:byte;
begin
  X68Sound_WaveFunc(WaveFuncTimeout);
//  X68Sound_WaveFunc(nil);
  exit;

  cnt:=MDX.MaxChannel;
  MDX.RunPCM8ppFlag:=False;
  for ch:=8 to cnt do begin
    if MMLChannel[ch].ppEnabled=True then begin
      MDX.RunPCM8ppFlag:=True;
    end;
  end;
  if MDX.RunPCM8ppFlag=True then
    X68Sound_WaveFunc(WaveFuncTimeout)
    else
    X68Sound_WaveFunc(nil);
end;

procedure TMXDRVmDLL.CalcPCM8ppTable;
var
  FreqCnt:integer;
  procedure MakeTable(var PosTable:PIntegerArray;var ModTable:PIntegerArray;Freq:word);
  var
    cnt:integer;
    fPos:double;
  begin
    if PosTable<>nil then begin
      GlobalFree(HGLOBAL(PosTable));
      PosTable:=nil;
    end;
    if ModTable<>nil then begin
      GlobalFree(HGLOBAL(ModTable));
      ModTable:=nil;
    end;
    PosTable:=Ptr(GlobalAlloc(GMEM_FIXED+GMEM_ZEROINIT,NowPCMRate*4));
    ModTable:=Ptr(GlobalAlloc(GMEM_FIXED+GMEM_ZEROINIT,NowPCMRate*4));
    for cnt:=0 to NowPCMRate-1 do begin
      fPos:=(cnt/NowPCMRate*Freq);
      PosTable[cnt]:=trunc(fPos);
      ModTable[cnt]:=byte(trunc(fPos*$100) mod $100);
    end;
  end;
begin
  if ppConvCalced=True then exit;

  for FreqCnt:=1 to ppFreqMax-1 do begin
    MakeTable(ppConvPosTables[FreqCnt],ppConvModTables[FreqCnt],ppFreqTable[FreqCnt]);
  end;
  ppConvCalced:=True;
end;

function TMXDRVmDLL.RunPCM8pp_V211:longword;
var
  cnt,ch:byte;
  tp0,tp1,tpm,tpl,tpr:longint;
  MstSamplePos:longint;
  PCMMod:longint;
begin
  // マーキュリー用データを再生する場合は、範囲チェック無しでコンパイルすること

  tpl:=0;
  tpr:=0;

  cnt:=MDX.MaxChannel;
  for ch:=8 to cnt do begin
    with MMLChannel[Ch] do begin
      if ppEnabled=True then begin
        MstSamplePos:=(longint(ppOffset div NowPCMRate)*ppFreq)+ppConvPosTable[ppOffset mod NowPCMRate];
        PCMMod:=ppConvModTable[ppOffset mod NowPCMRate];
        inc(ppOffset);
        case ppConvFunc of
          ppConvFunc_ADPCM: begin
            if ((ppDataSize*2-4)<=MstSamplePos) or (ADPCM[ppKeycode].PCMData=nil) then begin
              ppEnabled:=False;
              CheckppAllChannel;
              end else begin
              with ADPCM[ppKeycode] do begin
                case ADPCMSRCMode of
                  ADPCMSRCMode_Nearest: tpm:=longint(PCMData[MstSamplePos])*ppVolume16 div 16;
                  ADPCMSRCMode_Linear:  tpm:=(((longint(PCMData[MstSamplePos+0])*($100-PCMMod))+(longint(PCMData[MstSamplePos+1])*PCMMod)) div $100)*ppVolume16 div 16;
                  else tpm:=0;
                end;
                case ppPanpot of
                  1: inc(tpl,tpm);
                  2: inc(tpr,tpm);
                  3: begin
                    inc(tpl,tpm);
                    inc(tpr,tpm);
                  end;
                end;
              end;
            end;
          end;
          ppConvFunc_Mono8bit: begin
            MstSamplePos:=MstSamplePos*1;
            if (ppDataSize-2)<=MstSamplePos then begin
              ppEnabled:=False;
              CheckppAllChannel;
              end else begin
              tp0:=smallint(ppData[MstSamplePos+0]) shl 5;
              tp1:=smallint(ppData[MstSamplePos+1]) shl 5;
              tpm:=(((tp0*($100-PCMMod))+(tp1*PCMMod)) div $100)*ppVolume16 div 16;
              case ppPanpot of
                1: inc(tpl,tpm);
                2: inc(tpr,tpm);
                3: begin
                  inc(tpl,tpm);
                  inc(tpr,tpm);
                end;
              end;
            end;
          end;
          ppConvFunc_Mono16bit: begin
            MstSamplePos:=MstSamplePos*2;
            if (ppDataSize-4)<=MstSamplePos then begin
              ppEnabled:=False;
              CheckppAllChannel;
              end else begin
              tp0:=smallint(word(ppData[MstSamplePos+1])+word(ppData[MstSamplePos+0]) shl 8);
              tp1:=smallint(word(ppData[MstSamplePos+3])+word(ppData[MstSamplePos+2]) shl 8);
              tpm:=(((tp0*($100-PCMMod))+(tp1*PCMMod)) div $100)*ppVolume16 div 16;
              case ppPanpot of
                1: inc(tpl,tpm);
                2: inc(tpr,tpm);
                3: begin
                  inc(tpl,tpm);
                  inc(tpr,tpm);
                end;
              end;
            end;
          end;
          ppConvFunc_Stereo8bit: begin
            MstSamplePos:=MstSamplePos*2;
            if (ppDataSize-4)<=MstSamplePos then begin
              ppEnabled:=False;
              CheckppAllChannel;
              end else begin
              case ppPanpot of
                1: begin
                  tp0:=smallint(ppData[MstSamplePos+0]) shl 5;
                  tp1:=smallint(ppData[MstSamplePos+2]) shl 5;
                  inc(tpl,(((tp0*($100-PCMMod))+(tp1*PCMMod)) div $100)*ppVolume16 div 16);
                end;
                2: begin
                  tp0:=smallint(ppData[MstSamplePos+1]) shl 5;
                  tp1:=smallint(ppData[MstSamplePos+3]) shl 5;
                  inc(tpr,(((tp0*($100-PCMMod))+(tp1*PCMMod)) div $100)*ppVolume16 div 16);
                end;
                3: begin
                  tp0:=smallint(ppData[MstSamplePos+0]) shl 5;
                  tp1:=smallint(ppData[MstSamplePos+2]) shl 5;
                  inc(tpl,(((tp0*($100-PCMMod))+(tp1*PCMMod)) div $100)*ppVolume16 div 16);
                  tp0:=smallint(ppData[MstSamplePos+1]) shl 5;
                  tp1:=smallint(ppData[MstSamplePos+3]) shl 5;
                  inc(tpr,(((tp0*($100-PCMMod))+(tp1*PCMMod)) div $100)*ppVolume16 div 16);
                end;
              end;
            end;
          end;
          ppConvFunc_Stereo16bit: begin
            MstSamplePos:=MstSamplePos*4;
            if (ppDataSize-8)<=MstSamplePos then begin
              ppEnabled:=False;
              CheckppAllChannel;
              end else begin
              case ppPanpot of
                1: begin
                  tp0:=smallint(word(ppData[MstSamplePos+1])+word(ppData[MstSamplePos+0]) shl 8);
                  tp1:=smallint(word(ppData[MstSamplePos+5])+word(ppData[MstSamplePos+4]) shl 8);
                  inc(tpl,(((tp0*($100-PCMMod))+(tp1*PCMMod)) div $100)*ppVolume16 div 16);
                end;
                2: begin
                  tp0:=smallint(word(ppData[MstSamplePos+3])+word(ppData[MstSamplePos+2]) shl 8);
                  tp1:=smallint(word(ppData[MstSamplePos+7])+word(ppData[MstSamplePos+6]) shl 8);
                  inc(tpr,(((tp0*($100-PCMMod))+(tp1*PCMMod)) div $100)*ppVolume16 div 16);
                end;
                3: begin
                  tp0:=smallint(word(ppData[MstSamplePos+1])+word(ppData[MstSamplePos+0]) shl 8);
                  tp1:=smallint(word(ppData[MstSamplePos+5])+word(ppData[MstSamplePos+4]) shl 8);
                  inc(tpl,(((tp0*($100-PCMMod))+(tp1*PCMMod)) div $100)*ppVolume16 div 16);
                  tp0:=smallint(word(ppData[MstSamplePos+3])+word(ppData[MstSamplePos+2]) shl 8);
                  tp1:=smallint(word(ppData[MstSamplePos+7])+word(ppData[MstSamplePos+6]) shl 8);
                  inc(tpr,(((tp0*($100-PCMMod))+(tp1*PCMMod)) div $100)*ppVolume16 div 16);
                end;
              end;
            end;
          end;
          ppConvFunc_NotSupport: begin
          end;
        end;
      end;
    end;
  end;

  if (tpl=0) and (tpr=0) then begin
    result:=0;
    exit;
  end;

  if ((MDX.MasterVolume=$ff) and (MarcuryVolume=1024)) then begin
    end else begin
    if MarcuryVolume=1024 then begin
      tpl:=(tpl*MDX.MasterVolume div $ff);
      tpr:=(tpr*MDX.MasterVolume div $ff);
      end else begin
      tpl:=(tpl*MDX.MasterVolume div $ff)*MarcuryVolume div 1024;
      tpr:=(tpr*MDX.MasterVolume div $ff)*MarcuryVolume div 1024;
    end;
  end;
  if tpl<-$8000 then tpl:=-$8000;
  if tpl>$ffff then tpl:=$ffff;
  if tpr<-$8000 then tpr:=-$8000;
  if tpr>$ffff then tpr:=$ffff;

  if tpl<0 then tpl:=$10000+tpl;
  if tpr<0 then tpr:=$10000+tpr;
  result:=(word(tpr) shl 16)+word(tpl);
end;

procedure TMXDRVmDLL.FreeMemory;
var
  PDXNo:word;
  FreqCnt:integer;
  procedure FreeTable(var PosTable:PIntegerArray;var ModTable:PIntegerArray);
  begin
    if PosTable<>nil then begin
      GlobalFree(HGLOBAL(PosTable));
      PosTable:=nil;
    end;
    if ModTable<>nil then begin
      GlobalFree(HGLOBAL(ModTable));
      ModTable:=nil;
    end;
  end;
begin
  // ADPCM Free
  for PDXNo:=0 to ADPCMCount-1 do begin
    with ADPCM[PDXNo] do begin
      if Enabled=True then begin
        Enabled:=False;
        if ADPCMData<>nil then begin // MemoryFree
          GlobalFree(HGLOBAL(ADPCMData));
          ADPCMData:=nil;
        end;
        if PCMData<>nil then begin // MemoryFree
          GlobalFree(HGLOBAL(PCMData));
          PCMData:=nil;
        end;
      end;
    end;
  end;

  // PCM8ppTable Free
  if ppConvCalced=True then begin
    for FreqCnt:=1 to ppFreqMax-1 do begin
      FreeTable(ppConvPosTables[FreqCnt],ppConvModTables[FreqCnt]);
    end;
    ppConvCalced:=False;
  end;
end;

function TMXDRVmDLL.GetRealVolume(ch:integer):byte;
begin
  case NowDriverVersion of
    MXDRVDriverVersion210: begin
      Result:=MMLChannel[ch].Volume;
    end;
    MXDRVDriverVersion211: begin
      if ch<=7 then begin // OPM
        if MMLChannel[ch].VolMode=False then begin
          Result:=OPMVolTbl[MMLChannel[ch].Volume];
          end else begin
          Result:=MMLChannel[ch].Volume;
        end;
        end else begin // ADPCM
        if MMLChannel[ch].VolMode=False then begin
          Result:=MMLChannel[ch].Volume*8;
          end else begin
          Result:=PCMVolTbl[$7f-MMLChannel[ch].Volume]*8;
        end;
      end;
    end;
    else begin
      Result:=0;
    end;
  end;
end;

// -----------------------------------------------
// Public
// -----------------------------------------------

function MXDRVm_GetVersion:integer;
begin
  Result:=MXDRVmVersion;
end;

function MXDRVm_Init(PCMRate:integer;UseRomeo:boolean;DSoundSafeTime:integer):boolean;stdcall;
begin
  if MXDRVmEnabled=True then begin
    Result:=True;
    exit;
  end;

  MXDRVmDLL:=TMXDRVmDLL.Create;
  MXDRVmDLL.Init(PCMRate);

  if UseRomeo=False then begin
    MXDRVmEnabled:=X68Sound_Open(PCMRate);
    end else begin
    MXDRVmEnabled:=X68Sound_Open_withRomeo(PCMRate,DSoundSafeTime);
  end;

  Result:=MXDRVmEnabled;
end;

procedure MXDRVm_OPMEmuStopDisable;stdcall;
begin
  if MXDRVmEnabled=False then exit;

  X68Sound_Stop;
  X68Sound_Disable;
end;

procedure MXDRVm_FreeMemory;stdcall;
begin
  if MXDRVmEnabled=False then exit;

  MXDRVmDLL.FreeMemory;
  MXDRVmDLL.Free;
  MXDRVm_OPMEmuStopDisable;

  MXDRVmEnabled:=False;
end;

function MXDRVm_GetPCM(buf:PByteArray;len:LongInt):LongInt;stdcall;
begin
  Result:=X68Sound_GetPcm(buf,len);
end;

function MXDRVm_MDXLoad(MDXFilename:PChar):boolean;stdcall;
begin
  Result:=MXDRVmDLL.MDXLoad(MDXFilename);
end;

function MXDRVm_PDXLoad(PDXFilename:PChar):boolean;stdcall;
begin
  Result:=MXDRVmDLL.PDXLoad(PDXFilename);
end;

procedure MXDRVm_MDXReset;stdcall;
begin
  MXDRVmDLL.CalcPCM8ppTable;

  X68Sound_Stop;
  X68Sound_OPMSet($14,0);
  X68Sound_OpmInt(nil);
  X68Sound_WaveFunc(nil);

  PlayInfo.fPlayTimems:=0;
  PlayInfo.TotalClock:=0;
  PlayInfo.MesureClock:=0;

  MXDRVmDLL.MDXOPMRegisterInit;
  MXDRVmDLL.MMLMesure;
  MXDRVmDLL.MDXOPMRegisterInit;
  X68Sound_OPMSet($14,32+16+8+2);
  X68Sound_OpmInt(TimerBtimeout);
  X68Sound_WaveFunc(nil);
end;

procedure MXDRVm_MDXStop;stdcall;
var
  ch:integer;
begin
  for ch:=0 to 15 do begin
    if ch<=7 then
      MXDRVmDLL.SetOPMNoteoff(ch)
      else
      MXDRVmDLL.SetADPCMNoteoff(ch);
  end;
end;

procedure MXDRVm_StartFadeout;stdcall;
begin
  MXDRVmDLL.MDX.FadeoutFlag:=True;
end;

procedure MXDRVm_MMLSeek(SeekClock:integer);stdcall;
begin
  MXDRVmDLL.MMLSeek(SeekClock);
end;

procedure MXDRVm_SetPlus17Mode(m:boolean);stdcall;
begin
  MXDRVmDLL.Plus17Mode:=m;
end;

procedure MXDRVm_SetMarcuryVolume(vol:integer);stdcall;
begin
  MXDRVmDLL.MarcuryVolume:=vol;
end;

procedure MXDRVm_SetTransTempo(_TransTempo:integer);stdcall;
begin
  MXDRVmDLL.TransTempo:=_TransTempo;
  MXDRVmDLL.RefTempo;
end;

procedure MXDRVm_SetMute(Ch:byte;MuteFlag:boolean);stdcall;
begin
  MXDRVmDLL.SetMute(Ch,MuteFlag);
end;

procedure MXDRVm_GetInfomationMessage(msg:PChar);stdcall;
begin
  StrCpyToPChar(InfomationMessage,msg);
end;

procedure MXDRVm_ClearInfomationMessage;stdcall;
begin
  InfomationMessage:='';
end;

procedure MXDRVm_GetParamStr(Ch:byte;Line:integer;msg:PChar);stdcall;
var
  tmpstr:string;
  SetVol,NowDetune:integer;
begin
  with MXDRVmDLL.MMLChannel[Ch] do begin
    case Line of
      0: begin
        tmpstr:=Format('K:%2d  D:%4d  P:%8d Data:%s:%s',
                       [NowKeycode,Detune,NowPortament,
                        IntToHex(Cmd[4]*$10000+Cmd[3]*$100+Cmd[2],6),
                        IntToHex(Cmd[1]*$100+Cmd[0],4)]);
      end;
      1: begin
        SetVol:=MXDRVmDLL.GetRealVolume(Ch);
        SetVol:=SetVol-(MANowDetune div 256);
        if SetVol<0 then SetVol:=0;
        if 127<SetVol then SetVol:=127;
        if noteon=True then begin
          NowDetune:=MPNowDetune;
          end else begin
          NowDetune:=0;
        end;
        tmpstr:=Format('@%3d  @v:%3d SPLFO:%8d   Offset:%s',
                       [NowVoice,SetVol,NowDetune,IntToHex(NowPos,4)]);
      end;
      else tmpStr:='';
    end;
  end;

  StrCpyToPChar(tmpstr,msg);
end;

function MXDRVm_GetRealVolume(ch:integer):byte;stdcall;
begin
  Result:=MXDRVmDLL.GetRealVolume(ch);
end;

function MXDRVm_GetEndFlag:boolean;stdcall;
begin
  Result:=MXDRVmDLL.MDX.EndFlag;
end;

function MXDRVm_GetTotalClock:integer;stdcall;
begin
  Result:=PlayInfo.TotalClock;
end;

function MXDRVm_GetPlayTimems:double;stdcall;
begin
  Result:=PlayInfo.fPlayTimems;
end;

function MXDRVm_GetMesureClock:integer;stdcall;
begin
  Result:=PlayInfo.MesureClock;
end;

function MXDRVm_GetTempo:byte;stdcall;
begin
  Result:=MXDRVmDLL.MDX.Tempo;
end;

function MXDRVm_GetLoopCount:integer;stdcall;
begin
  Result:=MXDRVmDLL.MDX.LoopCount;
end;

function MXDRVm_GetVoice(ch:integer):integer;stdcall;
begin
  Result:=MXDRVmDLL.MMLChannel[ch].NowVoice;
end;

function MXDRVm_GetPanpot(ch:integer):byte;stdcall;
begin
  Result:=MXDRVmDLL.MMLChannel[ch].NowPanpot;
end;

function MXDRVm_GetKeycode(ch:integer):byte;stdcall;
begin
  Result:=MXDRVmDLL.MMLChannel[ch].NowKeycode;
end;

function MXDRVm_GetNoteon(ch:integer):boolean;stdcall;
begin
  Result:=MXDRVmDLL.MMLChannel[ch].Noteon;
end;

function MXDRVm_GetLastPitch(ch:integer):longint;stdcall;
begin
  Result:=MXDRVmDLL.MMLChannel[ch].LastPitch;
end;

procedure MXDRVm_SetTimerBEnabled(e:boolean);stdcall;
begin
  if e=True then begin
    X68Sound_OPMSet($14,32+16+8+2);
    X68Sound_OpmInt(TimerBtimeout);
    X68Sound_WaveFunc(nil);
    end else begin
    MXDRVm_MDXStop;
    X68Sound_OPMSet($14,0);
    X68Sound_OpmInt(nil);
    X68Sound_WaveFunc(nil);
  end;
end;

procedure MXDRVm_SetADPCMSRCMode(m:integer);stdcall;
begin
  ADPCMSRCMode:=m;
end;

// ----------------------------

exports
  MXDRVm_GetVersion,
  MXDRVm_Init,
  MXDRVm_OPMEmuStopDisable,
  MXDRVm_FreeMemory,
  MXDRVm_GetPCM,

  MXDRVm_MDXLoad,
  MXDRVm_PDXLoad,
  MXDRVm_MDXReset,
  MXDRVm_MDXStop,
  MXDRVm_StartFadeout,
  MXDRVm_MMLSeek,

  MXDRVm_SetPlus17Mode,
  MXDRVm_SetMarcuryVolume,
  MXDRVm_SetTransTempo,
  MXDRVm_SetMute,

  MXDRVm_GetInfomationMessage,
  MXDRVm_ClearInfomationMessage,
  MXDRVm_GetParamStr,
  MXDRVm_GetRealVolume,

  MXDRVm_GetEndFlag,
  MXDRVm_GetTotalClock,
  MXDRVm_GetPlayTimems,
  MXDRVm_GetMesureClock,
  MXDRVm_GetTempo,
  MXDRVm_GetLoopCount,
  MXDRVm_GetVoice,
  MXDRVm_GetPanpot,
  MXDRVm_GetKeycode,
  MXDRVm_GetNoteon,
  MXDRVm_GetLastPitch,
  MXDRVm_GetRealVolume,
  MXDRVm_SetTimerBEnabled,
  MXDRVm_SetADPCMSRCMode;

begin
  NowDriverVersion:=MXDRVDriverVersion211;
  InfomationMessage:='';
  PlayInfo.fPlayTimems:=0;
  PlayInfo.TotalClock:=0;
  PlayInfo.MesureClock:=0;

end.
