unit _PMDWin_Moonlight;

interface

uses
  Windows, ActiveX, SysUtils;

const
  _MAX_PATH=260;

  SOUND_55K=55555;
  SOUND_48K=48000;
  SOUND_44K=44100;
  SOUND_22K=22050;
  SOUND_11K=11025;

  PPZ8_i0=44100;
  PPZ8_i1=33080;
  PPZ8_i2=22050;
  PPZ8_i3=16540;
  PPZ8_i4=11025;
  PPZ8_i5= 8270;
  PPZ8_i6= 5513;
  PPZ8_i7= 4135;

type
  PPChar=^PChar;
  PByte=^Byte;
  Pword=^Word;
  PSmallInt=^SmallInt;

type
//=============================================================================
// IPCMMUSICDRIVER : 音源ドライバの基本的なインターフェイスを定義したクラス
//=============================================================================
  IPCMMUSICDRIVER = interface
    ['{9D4D6317-F40A-455E-9E2C-CB517556BA02}']
    function init(path:PChar):Boolean; stdcall;
    function music_load(filename:PChar):Integer; stdcall;
    function music_load2(musdata:Pointer; size:Integer):Integer; stdcall;
    function getmusicfilename(dest:PChar): PChar; stdcall;
    procedure music_start; stdcall;
    procedure music_stop; stdcall;
    function getloopcount:Integer; stdcall;
    function getlength(filename:PChar; var length:Integer; var loop:Integer):Boolean; stdcall;
    function getpos:Integer; stdcall;
    procedure setpos(pos:Integer); stdcall;
    procedure getpcmdata(buf:PSmallInt; nsamples:Integer); stdcall;
  end;

//=============================================================================
// IFMPMD : WinFMP, PMDWin に共通なインターフェイスを定義したクラス
//=============================================================================
  IFMPMD = interface(IPCMMUSICDRIVER)
    ['{81977D60-9496-4F20-A3BB-19B19943DA6D}']
    function loadrhythmsample(path:PChar):Boolean; stdcall;
    function setpcmdir(pcmdir:PChar):Boolean; stdcall;
    procedure setpcmrate(rate:Integer); stdcall;
    procedure setppzrate(rate:Integer); stdcall;
    procedure setfmcalc55k(flag:Boolean); stdcall;
    procedure setppzinterpolation(ip:Boolean); stdcall;
    procedure setfmwait(nsec:Integer); stdcall;
    procedure setssgwait(nsec:Integer); stdcall;
    procedure setrhythmwait(nsec:Integer); stdcall;
    procedure setadpcmwait(nsec:Integer); stdcall;
    procedure fadeout(speed:Integer); stdcall;
    procedure fadeout2(speed:Integer); stdcall;
    function getlength2(filename:PChar; var length:Integer; var loop:Integer):Boolean; stdcall;
    function getpos2:Integer; stdcall;
    procedure setpos2(pos:Integer); stdcall;
    function getpcmfilename(dest:PChar):PChar; stdcall;
    function getppzfilename(dest:PChar; bufnum:Integer):PChar; stdcall;
  end;

const IID_IPCMMUSICDRIVER:TIID=(D1:$9D4D6317; D2:$F40A; D3:$455E; D4:($9E,$2C,$CB,$51,$75,$56,$BA,$02));
const IID_IFMPMD:TIID=(D1:$81977D60; D2:$9496; D3:$4F20; D4:($A3,$BB,$19,$B1,$99,$43,$DA,$6D));

const
  PMDWIN_DLLNAME            ='PMDWin.dll';
  PMDWIN_MININTERFACEVERSION=021;    // Ver 0.21 以上
  PMDWIN_MAXINTERFACEVERSION=200;    // Ver 1.00 未満

  //  バージョン情報
  InterfaceVersion          = 117;    // PMDWin.dll のインターフェイスバージョン

  //  DLL の戻り値
  PMDWIN_OK           = 0; // 正常終了
  ERR_OPEN_MUSIC_FILE = 1; // 曲 データを開けなかった
  ERR_WRONG_MUSIC_FILE= 2; // PMD の曲データではなかった
  ERR_OPEN_PPC_FILE   = 3; // PPC を開けなかった
  ERR_OPEN_P86_FILE   = 4; // P86 を開けなかった
  ERR_OPEN_PPS_FILE   = 5; // PPS を開けなかった
  ERR_OPEN_PPZ1_FILE  = 6; // PPZ1 を開けなかった
  ERR_OPEN_PPZ2_FILE  = 7; // PPZ2 を開けなかった
  ERR_WRONG_PPC_FILE  = 8; // PPC/PVI ではなかった
  ERR_WRONG_P86_FILE  = 9; // P86 ではなかった
  ERR_WRONG_PPS_FILE  =10; // PPS ではなかった
  ERR_WRONG_PPZ1_FILE =11; // PVI/PZI ではなかった(PPZ1)
  ERR_WRONG_PPZ2_FILE =12; // PVI/PZI ではなかった(PPZ2)
  WARNING_PPC_ALREADY_LOAD =13; // PPC はすでに読み込まれている
  WARNING_P86_ALREADY_LOAD =14; // P86 はすでに読み込まれている
  WARNING_PPS_ALREADY_LOAD =15; // PPS はすでに読み込まれている
  WARNING_PPZ1_ALREADY_LOAD=16; // PPZ1 はすでに読み込まれている
  WARNING_PPZ2_ALREADY_LOAD=17; // PPZ2 はすでに読み込まれている

  ERR_WRONG_PARTNO  =30; // パート番号が不適
  ERR_ALREADY_MASKED=31; // 指定パートはすでにマスクされている
  ERR_NOT_MASKED    =32; // 指定パートはマスクされていない
  ERR_MUSIC_STOPPED =33; // 曲が止まっているのにマスク操作をした
  ERR_EFFECT_USED   =34; // 効果音で使用中なのでマスクを操作できない

  ERR_OUT_OF_MEMORY = 99; // メモリが足りない
  ERR_OTHER         =999; // その他のエラー

  //  PMDWin 専用の定義
  MAX_PCMDIR=64;

  //  その他定義
  NumOfFMPart        =6;
  NumOfSSGPart       =3;
  NumOfADPCMPart     =1;
  NumOFOPNARhythmPart=1;
  NumOfExtPart       =3;
  NumOfRhythmPart    =1;
  NumOfEffPart       =1;
  NumOfPPZ8Part      =8;
  NumOfAllPart       =(NumOfFMPart+NumOfSSGPart+NumOfADPCMPart+NumOFOPNARhythmPart+NumOfExtPart+NumOfRhythmPart+NumOfEffPart+NumOfPPZ8Part);

type
  // パートワークの定義
  PQQ=^TQQ;
  TQQ=record //  パートワークの構造体
    address   : PByte;    // 2 ｴﾝｿｳﾁｭｳ ﾉ ｱﾄﾞﾚｽ
    partloop  : PByte;    // 2 ｴﾝｿｳ ｶﾞ ｵﾜｯﾀﾄｷ ﾉ ﾓﾄﾞﾘｻｷ
    leng      : Integer;  // 1 ﾉｺﾘ LENGTH
    qdat      : Integer;  // 1 gatetime (q/Q値を計算した値)
    fnum      : Cardinal; // 2 ｴﾝｿｳﾁｭｳ ﾉ BLOCK/FNUM
    detune    : Integer;  // 2 ﾃﾞﾁｭｰﾝ
    lfodat    : Integer;  // 2 LFO DATA
    porta_num : Integer;  // 2 ポルタメントの加減値（全体）
    porta_num2: Integer;  // 2 ポルタメントの加減値（一回）
    porta_num3: Integer;  // 2 ポルタメントの加減値（余り）
    volume    : Integer;  // 1 VOLUME
    shift     : Integer;  // 1 ｵﾝｶｲ ｼﾌﾄ ﾉ ｱﾀｲ
    delay     : Integer;  // 1 LFO  [DELAY] 
    speed     : Integer;  // 1  [SPEED]
    step      : Integer;  // 1  [STEP]
    time      : Integer;  // 1  [TIME]
    delay2    : Integer;  // 1  [DELAY_2]
    speed2    : Integer;  // 1  [SPEED_2]
    step2     : Integer;  // 1  [STEP_2]
    time2     : Integer;  // 1  [TIME_2]
    lfoswi    : Integer;  // 1 LFOSW. B0/tone B1/vol B2/同期 B3/porta
                          //          B4/tone B5/vol B6/同期
    volpush    :Integer;  // 1 Volume PUSHarea
    mdepth     :Integer;  // 1 M depth
    mdspd      :Integer;  // 1 M speed
    mdspd2     :Integer;  // 1 M speed_2
    envf       :Integer;  // 1 PSG ENV. [START_FLAG] / -1でextend
    eenv_count :Integer;  // 1 ExtendPSGenv/No=0 AR=1 DR=2 SR=3 RR=4
    eenv_ar    :Integer;  // 1  /AR    /旧pat
    eenv_dr    :Integer;  // 1  /DR    /旧pv2
    eenv_sr    :Integer;  // 1  /SR    /旧pr1
    eenv_rr    :Integer;  // 1  /RR    /旧pr2
    eenv_sl    :Integer;  // 1  /SL
    eenv_al    :Integer;  // 1  /AL
    eenv_arc   :Integer;  // 1  /ARのカウンタ  /旧patb
    eenv_drc   :Integer;  // 1  /DRのカウンタ
    eenv_src   :Integer;  // 1  /SRのカウンタ  /旧pr1b
    eenv_rrc   :Integer;  // 1  /RRのカウンタ  /旧pr2b
    eenv_volume:Integer;  // 1  /Volume値(0〜15)/旧penv
    extendmode :Integer;  // 1 B1/Detune B2/LFO B3/Env Normal/Extend
    fmpan      :Integer;  // 1 FM Panning + AMD + PMD
    psgpat     :Integer;  // 1 PSG PATTERN [TONE/NOISE/MIX]
    voicenum   :Integer;  // 1 音色番号
    loopcheck  :Integer;  // 1 ループしたら１ 終了したら３
    carrier    :Integer;  // 1 FM Carrier
    slot1      :Integer;  // 1 SLOT 1 ﾉ TL
    slot3      :Integer;  // 1 SLOT 3 ﾉ TL
    slot2      :Integer;  // 1 SLOT 2 ﾉ TL
    slot4      :Integer;  // 1 SLOT 4 ﾉ TL
    slotmask   :Integer;  // 1 FM slotmask
    neiromask  :Integer;  // 1 FM 音色定義用maskdata
    lfo_wave   :Integer;  // 1 LFOの波形
    partmask   :Integer;  // 1 PartMask b0:通常 b1:効果音 b2:NECPCM用
                          //            b3:none b4:PPZ/ADE用 b5:s0時 b6:m b7:一時
    keyoff_flag:Integer;  // 1 KeyoffしたかどうかのFlag
    volmask    :Integer;  // 1 音量LFOのマスク
    qdata      :Integer;  // 1 qの値
    qdatb      :Integer;  // 1 Qの値
    hldelay    :Integer;  // 1 HardLFO delay
    hldelay_c  :Integer;  // 1 HardLFO delay Counter
    _lfodat    :Integer;  // 2 LFO DATA
    _delay     :Integer;  // 1 LFO  [DELAY] 
    _speed     :Integer;  // 1      [SPEED]
    _step      :Integer;  // 1      [STEP]
    _time      :Integer;  // 1      [TIME]
    _delay2    :Integer;  // 1      [DELAY_2]
    _speed2    :Integer;  // 1      [SPEED_2]
    _step2     :Integer;  // 1      [STEP_2]
    _time2     :Integer;  // 1      [TIME_2]
    _mdepth    :Integer;  // 1 M depth
    _mdspd     :Integer;  // 1 M speed
    _mdspd2    :Integer;  // 1 M speed_2
    _lfo_wave  :Integer;  // 1 LFOの波形
    _volmask   :Integer;  // 1 音量LFOのマスク
    mdc        :Integer;  // 1 M depth Counter (変動値)
    mdc2       :Integer;  // 1 M depth Counter
    _mdc       :Integer;  // 1 M depth Counter (変動値)
    _mdc2      :Integer;  // 1 M depth Counter
    onkai      :Integer;  // 1 演奏中の音階データ (0ffh:rest)
    sdelay     :Integer;  // 1 Slot delay
    sdelay_c   :Integer;  // 1 Slot delay counter
    sdelay_m   :Integer;  // 1 Slot delay Mask
    alg_fb     :Integer;  // 1 音色のalg/fb
    keyon_flag :Integer;  // 1 新音階/休符データを処理したらinc
    qdat2      :Integer;  // 1 q 最低保証値
    onkai_def  :Integer;  // 1 演奏中の音階データ (転調処理前 / ?fh:rest)
    shift_def  :Integer;  // 1 マスター転調値
    qdat3      :Integer;  // 1 q Random
  end;
  
  // OPEN_WORK の定義
  POPEN_WORK=^TOPEN_WORK;
  TOPEN_WORK=record
    MusPart:Array[0..NumOfAllPart-1] of PQQ;  // パートワークのポインタ
    mmlbuf        :PByte;   // Musicdataのaddress+1
    tondat        :PByte;   // Voicedataのaddress
    efcdat        :PByte;   // FM  Effecdataのaddress
    prgdat_adr    :PByte;   // 曲データ中音色データ先頭番地
    radtbl        :PWord;   // R part offset table 先頭番地
    rhyadr        :PByte;   // R part 演奏中番地
    rhythmmask    :Integer; // Rhythm音源のマスク x8c/10hのbitに対応
    fm_voldown    :Integer; // FM voldown 数値
    ssg_voldown   :Integer; // PSG voldown 数値
    pcm_voldown   :Integer; // ADPCM voldown 数値
    rhythm_voldown:Integer; // RHYTHM voldown 数値
    prg_flg       :Integer; // 曲データに音色が含まれているかflag
    x68_flg       :Integer; // OPM flag
    status        :Integer; // status1
    status2       :Integer; // status2
    tempo_d       :Integer; // tempo (TIMER-B)
    fadeout_speed :Integer; // Fadeout速度
    fadeout_volume:Integer; // Fadeout音量
    tempo_d_push  :Integer; // tempo (TIMER-B) / 保存用
    syousetu_lng  :Integer; // 小節の長さ
    opncount      :Integer; // 最短音符カウンタ
    TimerAtime    :Integer; // TimerAカウンタ
    effflag       :Integer; // PSG効果音発声on/off flag(ユーザーが代入)
    psnoi         :Integer; // PSG noise周波数
    psnoi_last    :Integer; // PSG noise周波数(最後に定義した数値)
    pcmstart      :Integer; // PCM音色のstart値
    pcmstop       :Integer; // PCM音色のstop値
    rshot_dat     :Integer; // リズム音源 shot flag
    rdat          :Array[0..6-1] of Integer;  //  リズム音源 音量/パンデータ
    rhyvol        :Integer; // リズムトータルレベル
    kshot_dat     :Integer; // ＳＳＧリズム shot flag
    play_flag     :Integer; // play flag
    fade_stop_flag:Integer; // Fadeout後 MSTOPするかどうかのフラグ
    kp_rhythm_flag:Boolean; // K/RpartでRhythm音源を鳴らすかflag
    pcm_gs_flag   :Integer; // ADPCM使用 許可フラグ (0で許可)
    slot_detune1  :Integer; // FM3 Slot Detune値 slot1
    slot_detune2  :Integer; // FM3 Slot Detune値 slot2
    slot_detune3  :Integer; // FM3 Slot Detune値 slot3
    slot_detune4  :Integer; // FM3 Slot Detune値 slot4
    TimerB_speed  :Integer; // TimerBの現在値(=ff_tempoならff中)
    fadeout_flag  :Integer; // 内部からfoutを呼び出した時1
    revpan        :Integer; // PCM86逆相flag
    pcm86_vol     :Integer; // PCM86の音量をSPBに合わせるか?
    syousetu      :Integer; // 小節カウンタ
    port22h       :Integer; // OPN-PORT 22H に最後に出力した値(hlfo)
    tempo_48      :Integer; // 現在のテンポ(clock=48 tの値)
    tempo_48_push :Integer; // 現在のテンポ(同上/保存用)
    _fm_voldown   :Integer; // FM voldown 数値 (保存用)
    _ssg_voldown  :Integer; // PSG voldown 数値 (保存用)
    _pcm_voldown  :Integer; // PCM voldown 数値 (保存用)
    _rhythm_voldow:Integer; // RHYTHM voldown 数値 (保存用)
    _pcm86_vol    :Integer; // PCM86の音量をSPBに合わせるか? (保存用)
    rshot_bd      :Integer; // リズム音源 shot inc flag (BD)
    rshot_sd      :Integer; // リズム音源 shot inc flag (SD)
    rshot_sym     :Integer; // リズム音源 shot inc flag (CYM)
    rshot_hh      :Integer; // リズム音源 shot inc flag (HH)
    rshot_tom     :Integer; // リズム音源 shot inc flag (TOM)
    rshot_rim     :Integer; // リズム音源 shot inc flag (RIM)
    rdump_bd      :Integer; // リズム音源 dump inc flag (BD)
    rdump_sd      :Integer; // リズム音源 dump inc flag (SD)
    rdump_sym     :Integer; // リズム音源 dump inc flag (CYM)
    rdump_hh      :Integer; // リズム音源 dump inc flag (HH)
    rdump_tom     :Integer; // リズム音源 dump inc flag (TOM)
    rdump_rim     :Integer; // リズム音源 dump inc flag (RIM)
    ch3mode       :Integer; // ch3 Mode
    ppz_voldown   :Integer; // PPZ8 voldown 数値
    _ppz_voldown  :Integer; // PPZ8 voldown 数値 (保存用)
    TimerAflag    :Integer; // TimerA割り込み中？フラグ
    TimerBflag    :Integer; // TimerB割り込み中？フラグ

    // for PMDWin
    rate          :Integer; // PCM 出力周波数(11k, 22k, 44k, 55k)
    ppz8ip        :Boolean; // PPZ8 で補完するか
    ppsip         :Boolean; // PPS  で補完するか
    p86ip         :Boolean; // P86  で補完するか
    use_p86       :Boolean; // P86  を使用しているか
    fadeout2_speed:Integer; // fadeout(高音質)speed(>0で fadeout)

    mus_filename:Array[0.._MAX_PATH-1] of char; // 曲のFILE名バッファ
    ppcfilename:Array[0.._MAX_PATH-1] of char; // PPC のFILE名バッファ
    pcmdir:Array[0..MAX_PCMDIR+1-1, 0.._MAX_PATH-1] of char; // PCM 検索ディレクトリ
  end;


  // OPEN_WORK の定義（−ファイル名部分他、、メモリ節約）
  POPEN_WORK2=^TOPEN_WORK2;      // OPEN_WORK - ファイル名部分
  TOPEN_WORK2=record
    MusPart:Array[0..NumOfAllPart-1] of PQQ;  // パートワークのポインタ
    mmlbuf        :PByte;   // Musicdataのaddress+1
    tondat        :PByte;   // Voicedataのaddress
    efcdat        :PByte;   // FM  Effecdataのaddress
    prgdat_adr    :PByte;   // 曲データ中音色データ先頭番地
    radtbl        :PWord;   // R part offset table 先頭番地
    rhyadr        :PByte;   // R part 演奏中番地
    rhythmmask    :Integer; // Rhythm音源のマスク x8c/10hのbitに対応
    fm_voldown    :Integer; // FM voldown 数値
    ssg_voldown   :Integer; // PSG voldown 数値
    pcm_voldown   :Integer; // ADPCM voldown 数値
    rhythm_voldown:Integer; // RHYTHM voldown 数値
    prg_flg       :Integer; // 曲データに音色が含まれているかflag
    x68_flg       :Integer; // OPM flag
    status        :Integer; // status1
    status2       :Integer; // status2
    tempo_d       :Integer; // tempo (TIMER-B)
    fadeout_speed :Integer; // Fadeout速度
    fadeout_volume:Integer; // Fadeout音量
    tempo_d_push  :Integer; // tempo (TIMER-B) / 保存用
    syousetu_lng  :Integer; // 小節の長さ
    opncount      :Integer; // 最短音符カウンタ
    TimerAtime    :Integer; // TimerAカウンタ
    effflag       :Integer; // PSG効果音発声on/off flag(ユーザーが代入)
    psnoi         :Integer; // PSG noise周波数
    psnoi_last    :Integer; // PSG noise周波数(最後に定義した数値)
    pcmstart      :Integer; // PCM音色のstart値
    pcmstop       :Integer; // PCM音色のstop値
    rshot_dat     :Integer; // リズム音源 shot flag
    rdat          :Array[0..6-1]of Integer;  //  リズム音源 音量/パンデータ
    rhyvol        :Integer; // リズムトータルレベル
    kshot_dat     :Integer; // ＳＳＧリズム shot flag
    play_flag     :Integer; // play flag
    fade_stop_flag:Integer; // Fadeout後 MSTOPするかどうかのフラグ
    kp_rhythm_flag:Boolean; // K/RpartでRhythm音源を鳴らすかflag
    pcm_gs_flag   :Integer; // ADPCM使用 許可フラグ (0で許可)
    slot_detune1  :Integer; // FM3 Slot Detune値 slot1
    slot_detune2  :Integer; // FM3 Slot Detune値 slot2
    slot_detune3  :Integer; // FM3 Slot Detune値 slot3
    slot_detune4  :Integer; // FM3 Slot Detune値 slot4
    TimerB_speed  :Integer; // TimerBの現在値(=ff_tempoならff中)
    fadeout_flag  :Integer; // 内部からfoutを呼び出した時1
    revpan        :Integer; // PCM86逆相flag
    pcm86_vol     :Integer; // PCM86の音量をSPBに合わせるか?
    syousetu      :Integer; // 小節カウンタ
    port22h       :Integer; // OPN-PORT 22H に最後に出力した値(hlfo)
    tempo_48      :Integer; // 現在のテンポ(clock=48 tの値)
    tempo_48_push :Integer; // 現在のテンポ(同上/保存用)
    _fm_voldown   :Integer; // FM voldown 数値 (保存用)
    _ssg_voldown  :Integer; // PSG voldown 数値 (保存用)
    _pcm_voldown  :Integer; // PCM voldown 数値 (保存用)
    _rhythm_voldow:Integer; // RHYTHM voldown 数値 (保存用)
    _pcm86_vol    :Integer; // PCM86の音量をSPBに合わせるか? (保存用)
    rshot_bd      :Integer; // リズム音源 shot inc flag (BD)
    rshot_sd      :Integer; // リズム音源 shot inc flag (SD)
    rshot_sym     :Integer; // リズム音源 shot inc flag (CYM)
    rshot_hh      :Integer; // リズム音源 shot inc flag (HH)
    rshot_tom     :Integer; // リズム音源 shot inc flag (TOM)
    rshot_rim     :Integer; // リズム音源 shot inc flag (RIM)
    rdump_bd      :Integer; // リズム音源 dump inc flag (BD)
    rdump_sd      :Integer; // リズム音源 dump inc flag (SD)
    rdump_sym     :Integer; // リズム音源 dump inc flag (CYM)
    rdump_hh      :Integer; // リズム音源 dump inc flag (HH)
    rdump_tom     :Integer; // リズム音源 dump inc flag (TOM)
    rdump_rim     :Integer; // リズム音源 dump inc flag (RIM)
    ch3mode       :Integer; // ch3 Mode
    ppz_voldown   :Integer; // PPZ8 voldown 数値
    _ppz_voldown  :Integer; // PPZ8 voldown 数値 (保存用)
    TimerAflag    :Integer; // TimerA割り込み中？フラグ
    TimerBflag    :Integer; // TimerB割り込み中？フラグ

    // for PMDWin
    rate          :Integer; // PCM 出力周波数(11k, 22k, 44k, 55k)
    ppz8ip        :Boolean; // PPZ8 で補完するか
    ppsip         :Boolean; // PPS  で補完するか
    p86ip         :Boolean; // P86  で補完するか
    use_p86       :Boolean; // P86  を使用しているか
    fadeout2_speed:Integer; // fadeout(高音質)speed(>0で fadeout)
  end;

  //===========================================================================
  // IPMDWIN:PMDWIN の Interface Class
  //===========================================================================
  IPMDWIN=interface(IFMPMD)
    ['{C07008F4-CAE0-421C-B08F-D8B319AFA4B4}']
    procedure setppsuse(value:Boolean); stdcall;
    procedure setrhythmwithssgeffect(value:Boolean); stdcall;
    procedure setpmd86pcmmode(value:Boolean); stdcall;
    function getpmd86pcmmode:Boolean; stdcall;
    procedure setppsinterpolation(ip:Boolean); stdcall;
    procedure setp86interpolation(ip:Boolean); stdcall;
    function maskon(ch:Integer):Integer; stdcall;
    function maskoff(ch:Integer):Integer; stdcall;
    procedure setfmvoldown(voldown:Integer); stdcall;
    procedure setssgvoldown(voldown:Integer); stdcall;
    procedure setrhythmvoldown(voldown:Integer); stdcall;
    procedure setadpcmvoldown(voldown:Integer); stdcall;
    procedure setppzvoldown(voldown:Integer); stdcall;
    function getfmvoldown:Integer; stdcall;
    function getfmvoldown2:Integer; stdcall;
    function getssgvoldown:Integer; stdcall;
    function getssgvoldown2:Integer; stdcall;
    function getrhythmvoldown:Integer; stdcall;
    function getrhythmvoldown2:Integer; stdcall;
    function getadpcmvoldown:Integer; stdcall;
    function getadpcmvoldown2:Integer; stdcall;
    function getppzvoldown:Integer; stdcall;
    function getppzvoldown2:Integer; stdcall;
    procedure setpos(pos:Integer); stdcall;
    procedure setpos2(pos:Integer); stdcall;
    function getpos:Integer; stdcall;
    function getpos2:Integer; stdcall;
    function getmemo(dest:PChar; musdata:Pointer; size, al:Integer):PChar; stdcall;
    function getmemo2(dest:PChar; musdata:Pointer; size, al:Integer):PChar; stdcall;
    function getmemo3(dest:PChar; musdata:Pointer; size, al:Integer):PChar; stdcall;
    function fgetmemo(dest:PChar; filename:PChar; al:Integer):Integer; stdcall;
    function fgetmemo2(dest:PChar; filename:PChar; al:Integer):Integer; stdcall;
    function fgetmemo3(dest:PChar; filename:PChar; al:Integer):Integer; stdcall;
    function getppcfilename(dest:PChar):PChar; stdcall;
    function getppsfilename(dest:PChar):PChar; stdcall;
    function getp86filename(dest:PChar):PChar; stdcall;
    function ppc_load(filename:PChar):Integer; stdcall;
    function pps_load(filename:PChar):Integer; stdcall;
    function p86_load(filename:PChar):Integer; stdcall;
    function ppz_load(filename:PChar; bufnum:Integer):Integer; stdcall;
    function getopenwork:POPEN_WORK; stdcall;
    function getpartwork(ch:Integer):PQQ; stdcall;
  end;

const
  IID_IPMDWIN:TIID =
    (D1:$C07008F4; D2:$CAE0; D3:$421C; D4:($B0,$8F,$D8,$B3,$19,$AF,$A4,$B4));
  CLSID_PMDWIN:TCLSID =
    (D1:$97C7C3F0; D2:$35D8; D3:$4304; D4:($8C,$1B,$AA,$92,$6E,$7A,$EC,$5C));

//=============================================================================
// DLL Interface
//=============================================================================
var
  HPMDWin:HMODULE;

  getversion:function:Integer; stdcall;
  getinterfaceversion:function:Integer; stdcall;
  pmd_CoCreateInstance:function(const rclsid: TCLSID; pUnkOuter: IUnknown; dwClsContext: Longint; const riid: TIID; var ppv): HResult; stdcall;

  pmdwininit:function(path:PChar):Boolean; stdcall;
  loadrhythmsample:function(path:PChar):Boolean; stdcall;
  setpcmdir:function(pcmdir:PChar):Boolean; stdcall;
  setpcmrate:procedure(rate:Integer); stdcall;
  setppzrate:procedure(rate:Integer); stdcall;
  setppsuse:procedure(value:Boolean); stdcall;
  setrhythmwithssgeffect:procedure(value:Boolean); stdcall;
  setpmd86pcmmode:procedure(value:Boolean); stdcall;
  getpmd86pcmmode:function:Boolean; stdcall;
  music_load:function(filename:PChar):Integer; stdcall;
  music_load2:function(musdata:Pointer; size:Integer):Integer; stdcall;
  music_start:procedure; stdcall;
  music_stop:procedure; stdcall;
  fadeout:procedure(speed:Integer); stdcall;
  fadeout2:procedure(speed:Integer); stdcall;
  getpcmdata:procedure(buf:PSmallInt; nsamples:Integer); stdcall;
  setfmcalc55k:procedure(flag:Boolean); stdcall;
  setppsinterpolation:procedure(ip:Boolean); stdcall;
  setp86interpolation:procedure(ip:Boolean); stdcall;
  setppzinterpolation:procedure(ip:Boolean); stdcall;
  getmemo:function(dest:PChar; musdata:Pointer; size, al:Integer):PChar; stdcall;
  getmemo2:function(dest:PChar; musdata:Pointer; size, al:Integer):PChar; stdcall;
  getmemo3:function(dest:PChar; musdata:Pointer; size, al:Integer):PChar; stdcall;
  fgetmemo:function(dest:PChar; filename:PChar; al:Integer):Integer; stdcall;
  fgetmemo2:function(dest:PChar; filename:PChar; al:Integer):Integer; stdcall;
  fgetmemo3:function(dest:PChar; filename:PChar; al:Integer):Integer; stdcall;
  getmusicfilename:function(dest:PChar):PChar; stdcall;
  getpcmfilename:function(dest:PChar):PChar; stdcall;
  getppcfilename:function(dest:PChar):PChar; stdcall;
  getppsfilename:function(dest:PChar):PChar; stdcall;
  getp86filename:function(dest:PChar):PChar; stdcall;
  getppzfilename:function(dest:PChar; bufnum:Integer):PChar; stdcall;
  ppc_load:function(filename:PChar):Integer; stdcall;
  pps_load:function(filename:PChar):Integer; stdcall;
  p86_load:function(filename:PChar):Integer; stdcall;
  ppz_load:function(filename:PChar; bufnum:Integer):Integer; stdcall;
  maskon:function(ch:Integer):Integer; stdcall;
  maskoff:function(ch:Integer):Integer; stdcall;
  setfmvoldown:procedure(voldown:Integer); stdcall;
  setssgvoldown:procedure(voldown:Integer); stdcall;
  setrhythmvoldown:procedure(voldown:Integer); stdcall;
  setadpcmvoldown:procedure(voldown:Integer); stdcall;
  setppzvoldown:procedure(voldown:Integer); stdcall;
  getfmvoldown:function:Integer; stdcall;
  getfmvoldown2:function:Integer; stdcall;
  getssgvoldown:function:Integer; stdcall;
  getssgvoldown2:function:Integer; stdcall;
  getrhythmvoldown:function:Integer; stdcall;
  getrhythmvoldown2:function:Integer; stdcall;
  getadpcmvoldown:function:Integer; stdcall;
  getadpcmvoldown2:function:Integer; stdcall;
  getppzvoldown:function:Integer; stdcall;
  getppzvoldown2:function:Integer; stdcall;
  setpos:procedure(pos:Integer); stdcall;
  setpos2:procedure(pos:Integer); stdcall;
  getpos:function:Integer; stdcall;
  getpos2:function:Integer; stdcall;
  getlength:function(filename:PChar; var length:Integer; var loop:Integer):Boolean; stdcall;
  getlength2:function(filename:PChar; var length:Integer; var loop:Integer):Boolean; stdcall;
  getloopcount:function:Integer; stdcall;
  setfmwait:procedure(nsec:Integer); stdcall;
  setssgwait:procedure(nsec:Integer); stdcall;
  setrhythmwait:procedure(nsec:Integer); stdcall;
  setadpcmwait:procedure(nsec:Integer); stdcall;
  getopenwork:function:POPEN_WORK; stdcall;
  getpartwork:function(ch:Integer):PQQ; stdcall;

function PMD_LoadDLL:boolean;
procedure PMD_FreeDLL;
function PMD_GetCopyright:string;

implementation

uses _const, _SimpleDialog;

function GetProcAddress2(hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall;
begin
  Result:=GetProcAddress(hModule,lpProcName);
  if(result=nil) then begin // 関数アドレスが取得できないと強制終了
    ShowMessage('PMDWin.DLL読み込みエラー','PMDWin.DLLが破損しています。');
    Halt;
  end;
end;

function PMD_LoadDLL:boolean;
begin
  HPMDWin := LoadLibrary(PMDWIN_DLLNAME);
  if(HPMDWin=0) then begin
    Result:=False;
    exit;
  end;

  // バージョンチェック
  getversion := GetProcAddress2(HPMDWin, 'getversion');
  getinterfaceversion := GetProcAddress2(HPMDWin, 'getinterfaceversion');

  if(getinterfaceversion < PMDWIN_MININTERFACEVERSION) then begin
    ShowMessage('PMDWin.DLL読み込みエラー','PMDWin.DLLはVer0.21〜0.99を使用してください。');
    Result:=False;
    exit;
  end;

  if(getinterfaceversion >= PMDWIN_MAXINTERFACEVERSION) then begin
    ShowMessage('PMDWin.DLL読み込みエラー','PMDWin.DLLはVer0.21〜0.99を使用してください。');
    Result:=False;
    exit;
  end;

  if (getversion=030) then begin
    ShowMessage('PMDWin.DLL読み込みエラー','PMDWin.DLL Ver0.30は推奨されないバージョンです。'+chr(13)+'Ver0.29以前かVer0.31以降を使うことをおすすめします。');
  end;

  // インスタンス取得関数
  pmd_CoCreateInstance := GetProcAddress2(HPMDWin, 'pmd_CoCreateInstance');

  // 残りの関数アドレスの取得
  pmdwininit := GetProcAddress2(HPMDWin, 'pmdwininit');
  loadrhythmsample := GetProcAddress2(HPMDWin, 'loadrhythmsample');
  setpcmdir := GetProcAddress2(HPMDWin, 'setpcmdir');
  setpcmrate := GetProcAddress2(HPMDWin, 'setpcmrate');
  setppzrate := GetProcAddress2(HPMDWin, 'setppzrate');
  setppsuse := GetProcAddress2(HPMDWin, 'setppsuse');
  setrhythmwithssgeffect := GetProcAddress2(HPMDWin, 'setrhythmwithssgeffect');
  setpmd86pcmmode := GetProcAddress2(HPMDWin, 'setpmd86pcmmode');
  getpmd86pcmmode := GetProcAddress2(HPMDWin, 'getpmd86pcmmode');
  music_load := GetProcAddress2(HPMDWin, 'music_load');
  music_load2 := GetProcAddress2(HPMDWin, 'music_load2');
  music_start := GetProcAddress2(HPMDWin, 'music_start');
  music_stop := GetProcAddress2(HPMDWin, 'music_stop');
  fadeout := GetProcAddress2(HPMDWin, 'fadeout');
  fadeout2 := GetProcAddress2(HPMDWin, 'fadeout2');
  getpcmdata := GetProcAddress2(HPMDWin, 'getpcmdata');
  setfmcalc55k := GetProcAddress2(HPMDWin, 'setfmcalc55k');
  setppsinterpolation := GetProcAddress2(HPMDWin, 'setppsinterpolation');
  setp86interpolation := GetProcAddress2(HPMDWin, 'setp86interpolation');
  setppzinterpolation := GetProcAddress2(HPMDWin, 'setppzinterpolation');
  getmemo := GetProcAddress2(HPMDWin, 'getmemo');
  getmemo2 := GetProcAddress2(HPMDWin, 'getmemo2');
  getmemo3 := GetProcAddress2(HPMDWin, 'getmemo3');
  fgetmemo := GetProcAddress2(HPMDWin, 'fgetmemo');
  fgetmemo2 := GetProcAddress2(HPMDWin, 'fgetmemo2');
  fgetmemo3 := GetProcAddress2(HPMDWin, 'fgetmemo3');
  getmusicfilename := GetProcAddress2(HPMDWin, 'getmusicfilename');
  getpcmfilename := GetProcAddress2(HPMDWin, 'getpcmfilename');
  getppcfilename := GetProcAddress2(HPMDWin, 'getppcfilename');
  getppsfilename := GetProcAddress2(HPMDWin, 'getppsfilename');
  getp86filename := GetProcAddress2(HPMDWin, 'getp86filename');
  getppzfilename := GetProcAddress2(HPMDWin, 'getppzfilename');
  ppc_load := GetProcAddress2(HPMDWin, 'ppc_load');
  pps_load := GetProcAddress2(HPMDWin, 'pps_load');
  p86_load := GetProcAddress2(HPMDWin, 'p86_load');
  ppz_load := GetProcAddress2(HPMDWin, 'ppz_load');
  maskon := GetProcAddress2(HPMDWin, 'maskon');
  maskoff := GetProcAddress2(HPMDWin, 'maskoff');
  setfmvoldown := GetProcAddress2(HPMDWin, 'setfmvoldown');
  setssgvoldown := GetProcAddress2(HPMDWin, 'setssgvoldown');
  setrhythmvoldown := GetProcAddress2(HPMDWin, 'setrhythmvoldown');
  setadpcmvoldown := GetProcAddress2(HPMDWin, 'setadpcmvoldown');
  setppzvoldown := GetProcAddress2(HPMDWin, 'setppzvoldown');
  getfmvoldown := GetProcAddress2(HPMDWin, 'getfmvoldown');
  getfmvoldown2 := GetProcAddress2(HPMDWin, 'getfmvoldown2');
  getssgvoldown := GetProcAddress2(HPMDWin, 'getssgvoldown');
  getssgvoldown2 := GetProcAddress2(HPMDWin, 'getssgvoldown2');
  getrhythmvoldown := GetProcAddress2(HPMDWin, 'getrhythmvoldown');
  getrhythmvoldown2 := GetProcAddress2(HPMDWin, 'getrhythmvoldown2');
  getadpcmvoldown := GetProcAddress2(HPMDWin, 'getadpcmvoldown');
  getadpcmvoldown2 := GetProcAddress2(HPMDWin, 'getadpcmvoldown2');
  getppzvoldown := GetProcAddress2(HPMDWin, 'getppzvoldown');
  getppzvoldown2 := GetProcAddress2(HPMDWin, 'getppzvoldown2');
  setpos := GetProcAddress2(HPMDWin, 'setpos');
  setpos2 := GetProcAddress2(HPMDWin, 'setpos2');
  getpos := GetProcAddress2(HPMDWin, 'getpos');
  getpos2 := GetProcAddress2(HPMDWin, 'getpos2');
  getlength := GetProcAddress2(HPMDWin, 'getlength');
  getlength2 := GetProcAddress2(HPMDWin, 'getlength2');
  getloopcount := GetProcAddress2(HPMDWin, 'getloopcount');
  setfmwait := GetProcAddress2(HPMDWin, 'setfmwait');
  setssgwait := GetProcAddress2(HPMDWin, 'setssgwait');
  setrhythmwait := GetProcAddress2(HPMDWin, 'setrhythmwait');
  setadpcmwait := GetProcAddress2(HPMDWin, 'setadpcmwait');
  getopenwork := GetProcAddress2(HPMDWin, 'getopenwork');
  getpartwork := GetProcAddress2(HPMDWin, 'getpartwork');

  Result:=True;
end;

procedure PMD_FreeDLL;
begin
  if(HPMDWin <> 0) then
    FreeLibrary(HPMDWin);
end;

function PMD_GetCopyright:string;
begin
  Result:='PMD for Windows 「PMDWin」'+format('Ver%1.2f InterfaceVer%1.2f',[getversion/100,getinterfaceversion/100])+CRLF;
  Result:=Result+'Copyright & Programmed by C60'+CRLF+CRLF;

  Result:=Result+'FM Sound Generator with OPN/OPM interface (fmgen 007a)'+CRLF;
  Result:=Result+'Copyright (C) by cisc 1998, 2003.'+CRLF+CRLF;

  Result:=Result+'PMD98 by KAJA'+CRLF+'PPZ8 by Ukky'+CRLF+CRLF;
end;

end.
