unit _MXDRVm;

{$WARN UNIT_PLATFORM OFF}
{$WARN SYMBOL_PLATFORM OFF}

interface

uses
  Windows, SysUtils, MMSystem, _SndDrv_const,_Vis_const;

type
  TInfomation=record
    FileSize:integer;
    PDXFileLoadFlag:boolean;
    PDXFilename:string;
    PDXFileSize:integer;
  end;

type
  TMXDRVm = class
  private
    { Private 宣言 }
    MemSync:TMultiReadExclusiveWriteSynchronizer;
    MCh:array[0..15] of TMCh;
    TransTempo:integer;
    NowPCMRate:integer;
    NowUseRomeo:boolean;
    NowDSoundSafeTime:integer;
    procedure MainInfomationVisible(MesStr:string);
    function  MDXLoad(MDXFilename:string):boolean;
    function  PDXLoad(MDXFilename:string):boolean;
    function  GetParamStr0(Ch:byte):string;
    function  GetParamStr1(Ch:byte):string;
    function  GetLoopCount:integer;
    function  GetTempo:byte;
    function  GetPlayTimems:double;
  public
    Infomation:TInfomation;
    function Init(PCMRate:integer;UseRomeo:boolean;DSoundSafeTime:integer):boolean;
    function ChangeRate(rate:integer):boolean;
    procedure RefrectionSetting;
    procedure GetPCM(buf:PByteArray;len:LongInt);
    procedure StartFadeout;
    function  MDXPlay:boolean;
    procedure MDXStop;
    procedure MMLSeek(SeekClock:integer);
    procedure MMLTrap;
    procedure GetVisual(var pSetVisual:pVisual);
    procedure GetVisualSystem(var pSetVisual:pVisual);
    function  GetTotalClock:integer;
    function  GetMesureClock:integer;
    function  GetDispClock:integer;
    procedure SetMute(Ch:byte;MuteFlag:boolean);
    procedure SetTransTempo(_TransTempo:integer);
    procedure SetTimerBEnabled(e:boolean);
    procedure SetADPCMSRCMode(m:integer);
    procedure FreeMemory;
    function  GetCopyright:string;
  end;

implementation

uses MainWin,
     _MDXWinINI, _const,_m_Tools,_Vis, _MXDRVm_Moonlight;

// --------------------
// private
// --------------------

procedure TMXDRVm.MainInfomationVisible(MesStr:string);
begin
  Main.InfomationVisible(MesStr);
end;

function TMXDRVm.MDXLoad(MDXFilename:string):boolean;
begin
  Infomation.FileSize:=GetFileSize(MDXFilename);
  Result:=MXDRVm_MDXLoad(PChar(MDXFilename));
end;

function TMXDRVm.PDXLoad(MDXFilename:string):boolean;
var
  PDXFilename:string;
  ExistFlag:boolean;
  procedure CheckExists(Filename:string);
  begin
    if ExistFlag=False then begin
      if FileExists(Filename)=True then begin
        PDXFilename:=Filename;
        ExistFlag:=True;
      end;
    end;
  end;
begin
  Infomation.PDXFilename:='';
  Infomation.PDXFileSize:=0;
  Infomation.PDXFileLoadFlag:=False;

  ExistFlag:=False;

  PDXFilename:=ChangeFileExt(GetPDXFilename(MDXFilename),'');
  if PDXFilename='' then begin
    Result:=False;
    exit;
  end;

  if Main.gFileInfo.isNetworkMode=True then begin
    CheckExists(Main.Network.CFG.MXDRV_PDXPath+PDXFilename+'.pdx'); // ネットワークパス
    CheckExists(Main.Network.CFG.MXDRV_PDXPath+copy(PDXFilename,1,8)+'.pdx'); // ネットワークパス（８文字カット）
  end;

  CheckExists(ExtractFilePath(Main.gFileInfo.GetPlayPath)+PDXFilename+'.pdx'); // MDXと同じフォルダ
  CheckExists(MXDRVmINI.PDXFilePath+'\'+PDXFilename+'.pdx'); // PDXファイルパス
  CheckExists(ExtractFilePath(Main.gFileInfo.GetPlayPath)+copy(PDXFilename,1,8)+'.pdx'); // MDXと同じフォルダ（８文字カット）
  CheckExists(MXDRVmINI.PDXFilePath+'\'+copy(PDXFilename,1,8)+'.pdx'); // PDXファイルパス（８文字カット）

  if ExistFlag=False then begin // PDXが見つからない
    if ExtractFilename(PDXFilename)<>'bos' then begin
      MainInfomationVisible('NotFound '+ExtractFilename(PDXFilename)+'.pdx');
    end;
    Result:=False;
    exit;
  end;

  Infomation.PDXFilename:=PDXFilename;
  Infomation.PDXFileSize:=GetFileSize(PDXFilename);
  Infomation.PDXFileLoadFlag:=MXDRVm_PDXLoad(PChar(PDXFilename));
  Result:=Infomation.PDXFileLoadFlag;
end;

function TMXDRVm.GetParamStr0(Ch:byte):string;
var
  Str:array[0..1024] of Char;
  PStr:PChar;
begin
  if Ch>=8 then begin
    Result:='';
    exit;
  end;

  ZeroMemory(@Str[0],1024);
  PStr:=Str;
  MXDRVm_GetParamStr(Ch,0,PStr);
  Result:=Str;
end;

function TMXDRVm.GetParamStr1(Ch:byte):string;
var
  Str:array[0..1024] of Char;
  PStr:PChar;
begin
  if Ch>=8 then begin
    Result:='';
    exit;
  end;

  ZeroMemory(@Str[0],1024);
  PStr:=Str;
  MXDRVm_GetParamStr(Ch,1,PStr);
  Result:=Str;
end;

function TMXDRVm.GetLoopCount:integer;
begin
  Result:=MXDRVm_GetLoopCount;
end;

function TMXDRVm.GetTempo:byte;
begin
  Result:=MXDRVm_GetTempo;
end;

function TMXDRVm.GetPlayTimems:double;
begin
  Result:=MXDRVm_GetPlayTimems;
end;

// --------------------
// public
// --------------------

function TMXDRVm.Init(PCMRate:integer;UseRomeo:boolean;DSoundSafeTime:integer):boolean;
begin
  MemSync:=TMultiReadExclusiveWriteSynchronizer.Create;

  MemSync.BeginWrite;

  NowPCMRate:=PCMRate;
  NowUseRomeo:=UseRomeo;
  NowDSoundSafeTime:=DSoundSafeTime;

  Result:=MXDRVm_LoadDLL;
  if Result=True then Result:=MXDRVm_Init(NowPCMRate,NowUseRomeo,NowDSoundSafeTime);

  MemSync.EndWrite;
end;

function TMXDRVm.ChangeRate(rate:integer):boolean;
begin
  MemSync.BeginWrite;

  NowPCMRate:=rate;

  MXDRVm_FreeMemory;
  Result:=MXDRVm_Init(NowPCMRate,NowUseRomeo,NowDSoundSafeTime);
  MemSync.EndWrite;
end;

procedure TMXDRVm.RefrectionSetting;
begin
  MemSync.BeginWrite;
  MXDRVm_SetPlus17Mode(True);
  MXDRVm_SetMarcuryVolume(MXDRVmINI.MarcuryVolume);
  MXDRVm_SetADPCMSRCMode(MXDRVmINI.ADPCMSRCMode);
  MemSync.EndWrite;
end;

procedure TMXDRVm.FreeMemory;
var
  WaitTick:dword;
begin
  MemSync.BeginWrite;
  if NowUseRomeo=True then begin
    SetTimerBEnabled(False);
    WaitTick:=timeGetTime;
    while ((WaitTick+dword(NowDSoundSafeTime*2))>timeGetTime) do begin
      sleep(16);
    end;
  end;
  if addr(MXDRVm_FreeMemory)<>nil then MXDRVm_FreeMemory;
  MXDRVm_FreeDLL;
  MemSync.EndWrite;

  MemSync.Free;
end;

procedure TMXDRVm.GetPCM(buf:PByteArray;len:LongInt);
begin
  SetTransTempo(TransTempo);
  MemSync.BeginWrite;
  MXDRVm_GetPCM(buf,len);
  MemSync.EndWrite;
end;

procedure TMXDRVm.StartFadeout;
begin
  MemSync.BeginWrite;
  if sdFadeout=False then begin
    sdFadeout:=True;
    MXDRVm_StartFadeout;
  end;
  MemSync.EndWrite;
end;

procedure TMXDRVm.MDXStop;
begin
  MemSync.BeginWrite;
  MXDRVm_MDXStop;
  MemSync.EndWrite;
end;

function TMXDRVm.MDXPlay;
var
  MDXFilename:string;
  Str:array[0..1024] of Char;
  PStr:PChar;
begin
  MemSync.BeginWrite;

  MDXFilename:=Main.gFileInfo.GetPlayPath;
  Result:=MDXLoad(MDXFilename);
  if Result=True then PDXLoad(MDXFilename);
  MXDRVm_MDXReset;

  ZeroMemory(@Str[0],1024);
  PStr:=Str;
  MXDRVm_GetInfomationMessage(PStr);
  if Str<>'' then begin
    Main.InfomationVisible(Str);
     MXDRVm_ClearInfomationMessage;
  end;

  MemSync.EndWrite;
end;

procedure TMXDRVm.MMLSeek(SeekClock:integer);
begin
  MemSync.BeginWrite;
  MXDRVm_MMLSeek(SeekClock);
  MemSync.EndWrite;
end;

procedure TMXDRVm.MMLTrap;
var
  Str:array[0..1024] of Char;
  PStr:PChar;
begin
  if sdEnd=True then begin
    MemSync.BeginWrite;
    sdLoop:=0;
    sdFadeout:=False;
    sdEnd:=True;
    MemSync.EndWrite;
    exit;
  end;

  MemSync.BeginWrite;

  sdLoop:=MXDRVm_GetLoopCount;

  if MXDRVm_GetEndFlag=True then begin
    sdEnd:=True;
    end else begin
    sdEnd:=False;
  end;

  ZeroMemory(@Str[0],1024);
  PStr:=Str;
  MXDRVm_GetInfomationMessage(PStr);
  if Str<>'' then begin
    Main.InfomationVisible(Str);
    MXDRVm_ClearInfomationMessage;
  end;

  MemSync.EndWrite;
end;

procedure TMXDRVm.GetVisual(var pSetVisual:pVisual);
var
  Ch:integer;
  tNoteNo,tVoiceNo:integer;
begin
  MemSync.BeginRead;

  for Ch:=0 to 15 do begin
    with pSetVisual.Channel[ch] do begin
      if Ch<=7 then begin
        mes0:=GetParamStr0(Ch);
        mes1:=GetParamStr1(Ch);
        end else begin
        mes0:='';
        mes1:='';
      end;
    end;
    if MXDRVm_GetNoteon(Ch)=False then begin // noteoff
      MCh[Ch].NoteonFlag:=False;
      Vis.SetAnalyzeNoteoff(Ch);
      end else begin
      tNoteNo:=MXDRVm_GetKeycode(Ch);
      tVoiceNo:=MXDRVm_GetVoice(Ch);
      pSetVisual.NoteKeyno[Ch]:=MXDRVm_GetLastPitch(Ch);
      if (MCh[Ch].NoteonFlag=False) or (MCh[Ch].Noteno<>tNoteNo) or (MCh[Ch].Voiceno<>tVoiceNo) then begin // noteon
        MCh[Ch].NoteonFlag:=True;
        MCh[Ch].Noteno:=tNoteNo;
        MCh[Ch].Voiceno:=tVoiceNo;
        Vis.SetAnalyzeVolume(Ch,MXDRVm_GetRealVolume(Ch));

        with PSetVisual.Channel[Ch] do begin
          Panpot:=MXDRVm_GetPanpot(Ch);
          Voice:=tVoiceNo;
          Keycode:=tNoteNo;
        end;
      end;
    end;
  end;

  MemSync.EndRead;
end;

procedure TMXDRVm.GetVisualSystem(var pSetVisual:pVisual);
begin
  MemSync.BeginRead;

  pSetVisual.PlayTime:=trunc(GetPlayTimems);
  pSetVisual.TotalClock:=GetTotalClock;
  pSetVisual.MesureClock:=GetMesureClock;
  pSetVisual.DispClock:=GetDispClock;
  pSetVisual.Tempo:=GetTempo;
  pSetVisual.LoopCount:=GetLoopCount;

  MemSync.EndRead;
end;

function TMXDRVm.GetTotalClock:integer;
begin
  MemSync.BeginRead;
  Result:=MXDRVm_GetTotalClock;
  MemSync.EndRead;
end;

function TMXDRVm.GetMesureClock:integer;
begin
  MemSync.BeginRead;
  Result:=MXDRVm_GetMesureClock;
  MemSync.EndRead;
end;

function TMXDRVm.GetDispClock:integer;
begin
  MemSync.BeginRead;
  Result:=MXDRVm_GetTotalClock;
  MemSync.EndRead;
end;

procedure TMXDRVm.SetMute(Ch:byte;MuteFlag:boolean);
begin
  MemSync.BeginWrite;
  MXDRVm_SetMute(ch,MuteFlag);
  MemSync.EndWrite;
end;

procedure TMXDRVm.SetTransTempo(_TransTempo:integer);
begin
  MemSync.BeginWrite;
  TransTempo:=_TransTempo;
  MXDRVm_SetTransTempo(TransTempo);
  MemSync.EndWrite;
end;

procedure TMXDRVm.SetTimerBEnabled(e:boolean);
begin
  MemSync.BeginWrite;
  if addr(MXDRVm_SetTimerBEnabled)<>nil then MXDRVm_SetTimerBEnabled(e);
  MemSync.EndWrite;
end;

procedure TMXDRVm.SetADPCMSRCMode(m:integer);
begin
  MemSync.BeginWrite;
  MXDRVm_SetADPCMSRCMode(m);
  MemSync.EndWrite;
end;

function TMXDRVm.GetCopyright:string;
begin
  MemSync.BeginRead;

  Result:='';

  Result:=Result+'mxdrv 2.06+16 Rel.1 (mxdrv16.x) original copyright 1988 milk'+CRLF;
  Result:=Result+'extend copyright 1988-91 K.MAEKAWA, Yatsube, Missy.M'+CRLF+CRLF;

  Result:=Result+'X68Sound.DLL X68k Sound Generator [2002/06/15] By Puusan'+CRLF;
  Result:=Result+'MXDRVm.DLL MXDRV Emulator Ver'+format('%.2f',[MXDRVm_GetVersion/100])+CRLF+CRLF;

  Result:=Result+'LZX decoder [lzx042.nas] from [_inmdx09s.lzh] by Mamiya 2000.'+CRLF+CRLF;

  Result:=Result+'カラオケPRO68k ver.最終版 by MEITEC!'+CRLF+CRLF;

  Result:=Result+'"PCM8" リアルタイム・ＡＤＰＣＭ多重再生ドライバー'+CRLF;
  Result:=Result+'         version 0.48b (C) 江藤　啓 1991,1992,1993'+CRLF+CRLF;

  Result:=Result+'"PCM8++" M-Unit Polyphonic PCM/ADPCM Driver'+CRLF;
  Result:=Result+'         version 0.83d (C)Tany 1994-1996'+CRLF+CRLF;

  MemSync.EndRead;
end;

end.
