Advertisement
Testaware

AmpMaster DLL v1.17.9.3 (x86)

Aug 30th, 2017
2,808
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ;************************************************************************************************
  2. ;* AmpMasterLibrary DLL (x86) v1.17.9 - 03.09.2017 13:53 - PB 5.44 LTS - Peace^TST
  3. ;* ----------------------------------------------------------------------------------------------
  4. ;* Unit for WinAmp In/Out Dlls x86 - no unicode!
  5. ;* ----------------------------------------------------------------------------------------------
  6. ;* https://testaware.wordpress.com
  7. ;************************************************************************************************
  8. ;EnableExplicit
  9.  
  10. #AMP_VER =  #PB_Compiler_Date
  11.  
  12. #IsAPI   =  1  ;* Windows API -> 1 = on / 0 = off (always off -> coz buggy API)
  13.  
  14. XIncludeFile   "Includes\i_amp_enumeration.pbi"
  15. XIncludeFile   "Includes\i_amp_structures.pbi"
  16. XIncludeFile   "Includes\i_amp_macros.pbi"
  17. XIncludeFile   "Includes\i_amp_player.pbi"
  18. XIncludeFile   "Includes\i_amp_table.pbi"
  19.  
  20. ; *** IDs for Subsongs: *.sid;*.mdat;*.tfm;*.tfx;*.nsf;*.gbs;*.fred
  21. #ID_FR10 =  ID_MAGIC($4E,$FA,$00,$10)  ; FRED10
  22. #ID_FR12 =  ID_MAGIC($4E,$FA,$00,$12)  ; FRED12
  23. #ID_FR4E =  ID_MAGIC($4E,$FA,$00,$4E)  ; FRED4E
  24. #ID_FR78 =  ID_MAGIC($4E,$FA,$00,$78)  ; FRED78
  25. #ID_FRSS =  $F1D4                      ; FRED SubSong (*.fred Word $6000 = 6 Songs $SN = always 0..6=7)
  26. #MAX_FRED=  %1111                      ; Max. Subsongs ($F/15) (random-crap)
  27.  
  28. #ID_GBS1 =  ID_MAGIC('G','B','S', 1 )  ; GBS1   =  *.gbs
  29. #ID_NESM =  ID_MAGIC('N','E','S','M')  ; NESM   =  *.nsf
  30. #ID_PSID =  ID_MAGIC('P','S','I','D')  ; PSID   =  *.sid
  31.  
  32. #ID_TFMX =  ID_MAGIC('T','F','M','X')  ; TFMX   =  mdat.*, *.tfm
  33. #ID_SONG =  ID_MAGIC('-','S','O','N')  ; TFMX-SON(G)
  34. #ID_TMOD =  ID_MAGIC('-','M','O','D')  ; TFMX-MERGED *.tfm
  35. #ID_2001 =  ID_MAGIC(' ', 0,  0,  1 )  ; TFMX-CUSTOM
  36. #ID_AMP0 =  ID_MAGIC('A','M','P', 0 )  ; TFMX-AMP0 = Private Tag (ReSet-SubSong) V1
  37.  
  38. DeclareCDLL Amp_Free()
  39.  
  40. ProcedureDLL   AttachProcess(Instance)
  41.  
  42.    Global   RS_WINAMP.RS_WINAMP        ; Winamp structure
  43.    Global   RS_AMPMASTER.RS_AMPMASTER  ; AmpMaster structure
  44.    Global   RS_AMPTIME.RS_AMPTIME      ; Intern timehandling structure
  45.  
  46.    Global   *i_n  =  ?i_n  ; s. include i_amp_table.pbi
  47.  
  48.    RS_AMPMASTER\ProgramName$  =  ProgramFilename()
  49.  
  50. EndProcedure
  51. ProcedureDLL   DetachProcess(Instance)
  52.    Amp_Free()
  53. EndProcedure
  54.  
  55. ProcedureC  Amp_Dummy(*pointer=#Null, numsamples=#Null, bps=#Null, nch=#Null);, srate=#Null, temp=#Null)
  56.    ProcedureReturn   numsamples
  57. EndProcedure
  58. ProcedureC  Amp_IsFile(*File)
  59.  
  60.    ;*************************************************************
  61.    ; Let's check for avail file to avoid loosy request by plugins
  62.    ; ------------------------------------------------------------
  63.    ; Return:   1 = file exist / 0 = file not found
  64.    ;*************************************************************
  65.    If *File =  #Null :  ProcedureReturn   #False   :  EndIf
  66.  
  67.    Protected   iStatus
  68.  
  69.    iStatus  =  FileSize(PeekS(*File))
  70.  
  71.    ProcedureReturn   Bool(iStatus > #Null)
  72.  
  73. EndProcedure
  74.  
  75. ProcedureCDLL  Amp_VersionStr(Flags.i)
  76.  
  77.    With  RS_AMPMASTER
  78.  
  79.       Protected   t$
  80.  
  81.       t$ =  StrU(Year(#AMP_VER)%1000)  +  "."   +
  82.             StrU(Month(#AMP_VER))      +  "."   +
  83.             StrU(Day(#AMP_VER))
  84.  
  85.       If Flags
  86.          t$ +  RSet(StrU(Hour(#AMP_VER)),    3)       +  ":"   +
  87.                RSet(StrU(Minute(#AMP_VER)),  2, "0")  +  ":"   +
  88.                RSet(StrU(Second(#AMP_VER)),  2, "0")
  89.       EndIf
  90.  
  91.       \Version$   =  #AMP_NAME$  +  " v1."   +  t$ +  " (x86)"
  92.  
  93.       ProcedureReturn   @\Version$
  94.  
  95.    EndWith
  96.  
  97. EndProcedure
  98.  
  99. ProcedureCDLL  Amp_Close()
  100.  
  101.    With  RS_WINAMP
  102.  
  103.       If \In2_DLL
  104.          If RS_AMPMASTER\IsPause
  105.             If \In2_Head\UnPause :  CallCFunctionFast(\In2_Head\UnPause)   :  EndIf
  106.          EndIf
  107.          If RS_AMPMASTER\IsPlay
  108.             If \In2_Head\Stop    :  CallCFunctionFast(\In2_Head\Stop)      :  EndIf
  109.          EndIf
  110.          If \In2_Head\Quit       :  CallCFunctionFast(\In2_Head\Quit)      :  EndIf
  111.       EndIf
  112.  
  113.       If \Out_DLL
  114.          If \Out_Head\Quit :  CallCFunctionFast(\Out_Head\Quit)   :  EndIf
  115.       EndIf
  116.  
  117.       If \In2_DLL :  MA_LibClose(\In2_DLL)   :  EndIf
  118.       If \Out_DLL :  MA_LibClose(\Out_DLL)   :  EndIf
  119.  
  120.    EndWith
  121.  
  122.    With  RS_AMPMASTER
  123.       \IsOpen  =  #False
  124.       \IsPause =  #False
  125.       \IsPlay  =  #False
  126.    EndWith
  127.  
  128.    ClearStructure(@RS_WINAMP, RS_WINAMP)
  129.    ClearStructure(@RS_AMPTIME,RS_AMPTIME)
  130.  
  131. EndProcedure
  132. ProcedureCDLL  Amp_Free()
  133.  
  134.    Amp_Close()
  135.  
  136.    ClearStructure(@RS_AMPMASTER, RS_AMPMASTER)
  137.  
  138. EndProcedure
  139. ProcedureCDLL  Amp_Init()
  140.  
  141.    Amp_Free()
  142.  
  143.    With  RS_AMPMASTER
  144.       \ProgramName$  =  ProgramFilename()
  145.       \Path$         =  GetPathPart(\ProgramName$) +  #DAMP_PATH$
  146.       \OutPath$      =  #DAMP_PATH$
  147.       \InPath$       =  #DAMP_PATH$
  148.       \InDll$        =  #DAMP_InDll$
  149.       \OutDll$       =  #DAMP_OUTDLL$
  150.       \Volume        =  #DAMP_VOLUME
  151.       \DefaultLength =  #DAMP_LENGTH
  152.    EndWith
  153.  
  154. EndProcedure
  155. ProcedureCDLL  Amp_Open()
  156.  
  157.    Protected   In_Ptr
  158.  
  159.    Amp_Close() ; Already open -> close all and clear RS_WINAMP structure
  160.  
  161.    With  RS_AMPMASTER
  162.  
  163.       ; Is path of AmpLibs -> or default -> "AmpLibs\"
  164.       If Len(\Path$)    =  #Null :  \Path$   =  GetPathPart(\ProgramName$) +  #DAMP_PATH$ :  EndIf
  165.       If Right(\Path$, 1)  <> "\":  \Path$   +  "\"   :  EndIf
  166.  
  167.       ; Set in_dll -> or use default one one -> "in_xmp.dll"
  168.       If Len(\InDll$)   =  #Null :  \InDll$  =  #DAMP_INDLL$   :  EndIf
  169.       If Len(\InPath$)  <  2     :  \InPath$ =  \Path$         :  EndIf
  170.  
  171.       ; Set out_dll -> or use default one -> "out_wave.dll"
  172.       If Len(\OutDll$)  =  #Null :  \OutDll$ =  #DAMP_OUTDLL$  :  EndIf
  173.       If Len(\OutPath$) <  2     :  \OutPath$=  \Path$         :  EndIf
  174.  
  175.       \InDll$  =  \InPath$    +  GetFilePart(\InDll$)
  176.       \OutDll$ =  \OutPath$   +  GetFilePart(\OutDll$)
  177.  
  178.       ; Check if in/out avail
  179.       If Amp_IsFile(@\InDll$) =  #False   :  RETURN_ERR(#EAMP_OPEN_INDLL)  :  EndIf
  180.       ;If   Amp_IsFile(@\OutDll$)=  #False   :  RETURN_ERR(#EAMP_OPEN_OUTDLL) :  EndIf
  181.  
  182.       If \WindowID   =  #Null :  \WindowID   =  GetForegroundWindow_()  :  EndIf
  183.  
  184.    EndWith
  185.  
  186.    ;************************************************
  187.    ; Initialize WinAmp In/Out - Libraries
  188.    ;************************************************
  189.    With  RS_WINAMP
  190.  
  191.       ; Set windowhandle -> or use foreground
  192.       \WindowID   =  RS_AMPMASTER\WindowID
  193.  
  194.       SetCurrentDirectory(RS_AMPMASTER\InPath$) ; Must set for sublibs & ini
  195.  
  196.       ; IN_DLL
  197.       ; -------------------------------------------------
  198.       MA_LibOpen(\In2_DLL, RS_AMPMASTER\InDll$)
  199.  
  200.       If \In2_DLL >  #Null
  201.  
  202.          MA_LibPtr(\In2_DLL, \In2_GeInModule2, "winampGetInModule2")
  203.  
  204.          If \In2_GeInModule2
  205.  
  206.             \In2_Head   =  CallCFunctionFast(\In2_GeInModule2)
  207.  
  208.             If \In2_Head   >  #Null
  209.  
  210.                \In2_Head\Version       =  #IN_VER
  211.                \In2_Head\hMainWindow   =  \WindowID
  212.                \In2_Head\hDllInstance  =  \In2_DLL
  213.  
  214.                CallCFunctionFast(\In2_Head\Init)
  215.  
  216.                ;dummy-routines (not used but needed)
  217.                \In2_Head\SAVSAInit     =  @Amp_Dummy()
  218.                \In2_Head\SAVSADeInit   =  @Amp_Dummy()
  219.                \In2_Head\SAAddPCMData  =  @Amp_Dummy()
  220.                \In2_Head\SAGetMode     =  @Amp_Dummy()
  221.                \In2_Head\SAAdd         =  @Amp_Dummy()
  222.                \In2_Head\VSAAddPCMData =  @Amp_Dummy()
  223.                \In2_Head\VSAGetMode    =  @Amp_Dummy()
  224.                \In2_Head\VSAAdd        =  @Amp_Dummy()
  225.                \In2_Head\VSASetInfo    =  @Amp_Dummy()
  226.                \In2_Head\dsp_isactive  =  @Amp_Dummy()
  227.                \In2_Head\dsp_dosamples =  @Amp_Dummy()
  228.                \In2_Head\EQSet         =  @Amp_Dummy()
  229.                \In2_Head\SetInfo       =  @Amp_Dummy()
  230.  
  231.                RS_AMPMASTER\InInfo$ =  PeekS(\In2_Head\description)
  232.  
  233.             EndIf
  234.          EndIf
  235.       EndIf
  236.  
  237.       If \In2_DLL <= #Null Or \In2_Head   <= #Null ; In-Error?
  238.          Amp_Close() :  RETURN_ERR(#EAMP_OPEN_INDLL)
  239.       EndIf
  240.  
  241.       ; OUT_DLL
  242.       ; -------------------------------------------------
  243.       If \In2_Head\UsesOutputPlug   ; does this plug-in use the output plug-ins?
  244.  
  245.          If Amp_IsFile(@RS_AMPMASTER\OutDll$)=  #False   :  RETURN_ERR(#EAMP_OPEN_OUTDLL) :  EndIf
  246.  
  247.          MA_LibOpen(\Out_DLL, RS_AMPMASTER\OutDll$)
  248.  
  249.          If \Out_DLL >  #Null
  250.  
  251.             MA_LibPtr(\Out_DLL, \Out_GetOutModule, "winampGetOutModule")
  252.  
  253.             \Out_Head   =  CallCFunctionFast(\Out_GetOutModule)
  254.  
  255.             If \Out_Head   >  #Null
  256.                \Out_Head\Version       =  #OUT_VER
  257.                \Out_Head\hMainWindow   =  \WindowID
  258.                \Out_Head\hDllInstance  =  \Out_DLL
  259.                CallCFunctionFast(\Out_Head\Init)
  260.             EndIf
  261.  
  262.          EndIf
  263.  
  264.          If \Out_DLL <= #Null Or \Out_Head   <= #Null ; Out-Error?
  265.             Amp_Close() :  RETURN_ERR(#EAMP_OPEN_OUTDLL)
  266.          EndIf
  267.  
  268.          \In2_Head\outMod        =  \Out_Head
  269.  
  270.          RS_AMPMASTER\OutInfo$   =  PeekS(\Out_Head\description)
  271.  
  272.       Else
  273.  
  274.          RS_AMPMASTER\OutInfo$   =  "No use of output plug-ins"
  275.  
  276.       EndIf
  277.  
  278.    EndWith
  279.  
  280.    RS_AMPMASTER\IsOpen  =  #True
  281.  
  282.    RETURN_ERR(#EAMP_OK)
  283.  
  284. EndProcedure
  285.  
  286. ProcedureCDLL  Amp_GetInFlags(*InLib)
  287.  
  288.    With  RS_AMPMASTER
  289.  
  290.       \InFlags =  #FAMP_DEFAULT
  291.  
  292.       If *InLib
  293.  
  294.          Protected   File$ =  GetFilePart(PeekS(*InLib))
  295.  
  296.          Protected   *i_x.RS_INTABLE   =  *i_n
  297.  
  298.          While *i_x\iFLG
  299.  
  300.             If StrCmpNI_(@*i_x\iLIB\s, @File$, Len(File$))  =  #Null
  301.                \InFlags =  PeekI(*i_x\iFLG)
  302.                Break
  303.             EndIf
  304.  
  305.             *i_x  +  SizeOf(RS_INTABLE)
  306.  
  307.          Wend
  308.  
  309.          If \IsPlay
  310.             If RS_WINAMP\In2_Head\is_seekable   =  #Null ; is this stream not seekable?
  311.                \InFlags|#FAMP_NO_SEEK
  312.             EndIf
  313.             If RS_WINAMP\In2_Head\UsesOutputPlug=  #Null ; doesn't this plug-in use output plug-ins?
  314.                \InFlags|#FAMP_NO_OUTPUT|#FAMP_NO_RECORD
  315.             EndIf
  316.          EndIf
  317.  
  318.       EndIf
  319.  
  320.       ProcedureReturn   \InFlags
  321.  
  322.    EndWith
  323.  
  324. EndProcedure
  325. ProcedureCDLL  Amp_GetAmpInFormatStr(*InLib)
  326.  
  327.    ; Returns all supported formats by given *InLib only as string
  328.  
  329.    With  RS_AMPMASTER
  330.  
  331.       Protected   File$ =  GetFilePart(PeekS(*InLib))
  332.       Protected   *i_x.RS_INTABLE   =  *i_n
  333.  
  334.       \InFormats$ =  #Empty$
  335.  
  336.       While *i_x\iFLG
  337.  
  338.          If StrCmpNI_(@*i_x\iLIB\s, @File$, Len(File$))  =  #Null
  339.             \InFormats$ =  *i_x\iEXT\s
  340.             Break
  341.          EndIf
  342.  
  343.          *i_x  +  SizeOf(RS_INTABLE)   ; Next in Table-Ptr
  344.  
  345.       Wend
  346.  
  347.       CharLower_(@\InFormats$)
  348.  
  349.       ProcedureReturn   @\InFormats$
  350.  
  351.    EndWith
  352.  
  353. EndProcedure
  354.  
  355. ;-
  356. ;- *** Play-Stuff ***
  357. ProcedureCDLL  Amp_MusicPlay(*File)
  358.  
  359.    ; Play musicfile, returns 0 if all ok
  360.  
  361.    With  RS_AMPMASTER
  362.  
  363.       If \IsOpen           =  #False   :  RETURN_ERR(#EAMP_INITIALIZE)  :  EndIf
  364.       If Amp_IsFile(*File) =  #False   :  RETURN_ERR(#EAMP_OPEN_FILE)   :  EndIf
  365.  
  366.       \MusicFile$ =  PeekS(*File)
  367.  
  368.       Amp_GetInFlags(@\InDll$)   ; get flags of in_dll
  369.  
  370.       If \InFlags&#FAMP_EX_SFX
  371.          If GetPathPart(\MusicFile$)
  372.             SetCurrentDirectory(GetPathPart(\MusicFile$))   ; Must set for miniusf, minipsf...
  373.          EndIf
  374.       Else
  375.          If GetCurrentDirectory()   <> \InPath$
  376.             SetCurrentDirectory(\InPath$) ; Must set for sublibs & ini
  377.          EndIf
  378.       EndIf
  379.  
  380.       ; Try to get Tag-Title and real length in ms by played file (*File=0 doesn't work for wma)
  381.       CallCFunctionFast(RS_WINAMP\In2_Head\GetFileInfo, *File, @\Buffer, @\MusicTime)
  382.  
  383.       ; Title of musicfile (eg. *.Mod)
  384.       If \Buffer
  385.          \MusicTitle$   =  \Buffer  ; get title
  386.       Else
  387.          \MusicTitle$   =  GetFilePart(\MusicFile$)   ; use filename
  388.       EndIf
  389.  
  390.       \MusicLength   =  \MusicTime  ; length in ms
  391.  
  392.       If CallCFunctionFast(RS_WINAMP\In2_Head\Play, *File)  <> #EAMP_OK ; Error?
  393.          RETURN_ERR(#EAMP_UNKOWN_FORMAT)
  394.       EndIf
  395.  
  396.       CallCFunctionFast(RS_WINAMP\In2_Head\SetVolume, \Volume) ; s. Amp_Init()
  397.       CallCFunctionFast(RS_WINAMP\In2_Head\SetPan,    \Pan)    ; s. Amp_Init()
  398.  
  399.       If RS_WINAMP\In2_Head\is_seekable   =  #Null
  400.          \InFlags|#FAMP_NO_SEEK
  401.       EndIf
  402.       If RS_WINAMP\In2_Head\UsesOutputPlug=  #Null
  403.          \InFlags|#FAMP_NO_OUTPUT|#FAMP_NO_RECORD
  404.       EndIf
  405.  
  406.       \IsPlay  =  #True
  407.  
  408.       ; No real playlength -> use getlength or length as default in ms (#DAMP_LENGTH)
  409.       If \MusicLength   <= 1000  ; length must > 1000ms
  410.  
  411.          \MusicLength   =  CallCFunctionFast(RS_WINAMP\In2_Head\GetLength) ; get playlength
  412.  
  413.          If \MusicLength   <= 1000  ; use default length?
  414.             \MusicLength   =  \DefaultLength ; s. Amp_SetDefaultLength(ms)
  415.          EndIf
  416.  
  417.       EndIf
  418.  
  419.    EndWith
  420.  
  421.    ; set starttime (EleapsedMilliseconds() equ 0)
  422.    With  RS_AMPTIME
  423.       \msStart =  MA_GetTime()
  424.       ;\msStop =  \msStart +  RS_AMPMASTER\MusicLength
  425.    EndWith
  426.  
  427.    RETURN_ERR(#EAMP_OK)
  428.  
  429. EndProcedure
  430. ProcedureCDLL  Amp_MusicPause(Pause.i)
  431.  
  432.    ; set/return status of pause (1=pause/0=unpause)
  433.    With  RS_AMPMASTER
  434.  
  435.       Pause =  Bool(Pause)
  436.  
  437.       If \IsPause <> Pause
  438.  
  439.          \IsPause =  Pause
  440.  
  441.          If \IsPlay
  442.             If \IsPause
  443.  
  444.                CallCFunctionFast(RS_WINAMP\In2_Head\Pause)
  445.  
  446.                RS_AMPTIME\msSleep   =  MA_GetTime()   ; ms until unpause
  447.  
  448.             Else
  449.  
  450.                CallCFunctionFast(RS_WINAMP\In2_Head\UnPause)
  451.  
  452.                RS_AMPTIME\msStart   +  (MA_GetTime()  -  RS_AMPTIME\msSleep)     ; refresh startime
  453.                ;RS_AMPTIME\msStart  =  MA_GetTime()   -  (RS_AMPTIME\msSleep  -  RS_AMPTIME\msStart)
  454.                ;RS_AMPTIME\msStop      =  RS_AMPTIME\msStart   +  RS_AMPMASTER\MusicLength   ; refresh finish
  455.  
  456.             EndIf
  457.          EndIf
  458.  
  459.       EndIf
  460.  
  461.       ProcedureReturn   \IsPause
  462.  
  463.    EndWith
  464.  
  465. EndProcedure
  466. ProcedureCDLL  Amp_MusicStop()
  467.  
  468.    With  RS_AMPMASTER
  469.       If \IsPlay
  470.          \IsPlay  =  #False
  471.          CallCFunctionFast(RS_WINAMP\In2_Head\Stop)
  472.       EndIf
  473.    EndWith
  474.  
  475. EndProcedure
  476. ProcedureCDLL  Amp_MusicSetVolume(Volume.i)
  477.  
  478.    With  RS_AMPMASTER
  479.  
  480.       If \Volume  <> Volume
  481.  
  482.          If Volume   <  #Null
  483.             Volume   =  0
  484.          ElseIf   Volume   >  255
  485.             Volume   =  255
  486.          EndIf
  487.  
  488.          \Volume  =  Volume
  489.  
  490.          If \IsOpen
  491.             CallCFunctionFast(RS_WINAMP\In2_Head\SetVolume, \Volume)
  492.          EndIf
  493.  
  494.       EndIf
  495.  
  496.       ProcedureReturn   \Volume
  497.  
  498.    EndWith
  499.  
  500. EndProcedure
  501. ProcedureCDLL  Amp_MusicSetPan(Pan.i)
  502.  
  503.    With  RS_AMPMASTER
  504.  
  505.       If \Pan  <> Pan
  506.  
  507.          If Pan   <  -127
  508.             Pan   =  -127
  509.          ElseIf   Pan   >  127
  510.             Pan   =  127
  511.          EndIf
  512.  
  513.          \Pan  =  Pan
  514.  
  515.          If \IsOpen
  516.             CallCFunctionFast(RS_WINAMP\In2_Head\SetPan, \Pan)
  517.          EndIf
  518.  
  519.       EndIf
  520.  
  521.       ProcedureReturn   \Pan
  522.  
  523.    EndWith
  524.  
  525. EndProcedure
  526. ProcedureCDLL  Amp_MusicIsPlaying()
  527.  
  528.    With  RS_AMPMASTER
  529.  
  530.       If \IsOpen  =  #Null
  531.          ProcedureReturn   #Null
  532.       ElseIf   RS_WINAMP\In2_Head\UsesOutputPlug
  533.          \IsPlay  =  CallCFunctionFast(RS_WINAMP\Out_Head\IsPlaying)
  534.       EndIf
  535.  
  536.       ProcedureReturn   \IsPlay
  537.  
  538.    EndWith
  539.  
  540. EndProcedure
  541. ProcedureCDLL  Amp_MusicGetLength(Flags.i)
  542.  
  543.    ;**************************************************************************************
  544.    ; Flags:    0=MusicLength  (eg. DefaultLength)
  545.    ;           1=MusicTime    (original length by in_dll)
  546.    ; -------------------------------------------------------------------------------------
  547.    ; Return: total length of music in ms
  548.    ;**************************************************************************************
  549.  
  550.    If Flags
  551.       ProcedureReturn   RS_AMPMASTER\MusicTime
  552.    EndIf
  553.  
  554.    ProcedureReturn   RS_AMPMASTER\MusicLength   ; Fast & full musiclength in ms -> s. Amp_MusicPlay (real length)
  555.  
  556. EndProcedure
  557. ProcedureCDLL  Amp_MusicGetPosition()
  558.    ;**************************************
  559.    ; Return:   current playposition in ms
  560.    ;**************************************
  561.    With  RS_WINAMP
  562.  
  563.       If RS_AMPMASTER\IsPlay
  564.  
  565.          If \In2_Head\is_seekable   And   RS_AMPMASTER\MusicLength   <> RS_AMPMASTER\DefaultLength
  566.             ProcedureReturn   CallCFunctionFast(\In2_Head\GetOutputTime)
  567.          ElseIf   \In2_Head\UsesOutputPlug
  568.             ProcedureReturn   CallCFunctionFast(\Out_Head\GetOutputTime)
  569.          EndIf
  570.  
  571.       EndIf
  572.  
  573.    EndWith
  574.  
  575.    ProcedureReturn   #Null
  576.  
  577. EndProcedure
  578. ProcedureCDLL  Amp_MusicGetOutPosition()
  579.    ;****************************************************
  580.    ; Important:   use this if in_player is a diskwriter!
  581.    ; Return:      written/saved size in ms
  582.    ;****************************************************
  583.    With  RS_AMPMASTER
  584.       If \IsPlay  And   RS_WINAMP\In2_Head\UsesOutputPlug
  585.          ProcedureReturn   CallCFunctionFast(RS_WINAMP\Out_Head\GetOutputTime)
  586.       EndIf
  587.    EndWith
  588.  
  589.    ProcedureReturn   #Null
  590.  
  591. EndProcedure
  592. ProcedureCDLL  Amp_MusicSetPosition(Milliseconds.i)
  593.    ;****************************************
  594.    ; Milliseconds:   position in ms
  595.    ; Return:         real playposition in ms
  596.    ;****************************************
  597.    With  RS_WINAMP
  598.  
  599.       If RS_AMPMASTER\IsOpen
  600.  
  601.          If \In2_Head\is_seekable
  602.  
  603.             If Milliseconds   <  #Null
  604.                Milliseconds   =  0
  605.             ElseIf   Milliseconds   >  RS_AMPMASTER\MusicLength
  606.                Milliseconds   =  RS_AMPMASTER\MusicLength
  607.             EndIf
  608.  
  609.             If RS_AMPMASTER\IsPlay
  610.  
  611.                CallCFunctionFast(\In2_Head\SetOutputTime, Milliseconds)
  612.  
  613.                If \In2_Head\UsesOutputPlug
  614.                   CallCFunctionFast(\Out_Head\Flush, Milliseconds)
  615.                EndIf
  616.  
  617.             EndIf
  618.  
  619.          Else
  620.  
  621.             Milliseconds   =  Amp_MusicGetPosition()  ;CallCFunctionFast(\Out_Head\GetOutputTime)  ; current position in ms
  622.  
  623.          EndIf
  624.  
  625.          ; Refresh starttime
  626.          RS_AMPTIME\msStart   =  MA_GetTime()   -  Milliseconds
  627.  
  628.          ProcedureReturn   Milliseconds
  629.  
  630.       EndIf
  631.  
  632.    EndWith
  633.  
  634. EndProcedure
  635. ProcedureCDLL  Amp_MusicGetTitleStr()
  636.    ProcedureReturn   @RS_AMPMASTER\MusicTitle$
  637. EndProcedure
  638.  
  639. ProcedureCDLL  Amp_InAbout()
  640.  
  641.    If RS_AMPMASTER\IsOpen  =  #False   :  RETURN_ERR(#EAMP_NO_INDLL) :  EndIf
  642.  
  643.    With  RS_WINAMP
  644.       If \In2_DLL And   \In2_Head\About   :  CallCFunctionFast(\In2_Head\About,  \WindowID)  :  EndIf
  645.    EndWith
  646.  
  647. EndProcedure
  648. ProcedureCDLL  Amp_InConfig()
  649.  
  650.    If RS_AMPMASTER\IsOpen  =  #False   :  RETURN_ERR(#EAMP_NO_INDLL) :  EndIf
  651.  
  652.    With  RS_WINAMP
  653.       If \In2_DLL And   \In2_Head\Config  :  CallCFunctionFast(\In2_Head\Config, \WindowID)  :  EndIf
  654.    EndWith
  655.  
  656. EndProcedure
  657.  
  658. ProcedureCDLL  Amp_OutAbout()
  659.  
  660.    If RS_AMPMASTER\IsOpen  =  #False   :  RETURN_ERR(#EAMP_NO_OUTDLL)   :  EndIf
  661.  
  662.    With  RS_WINAMP
  663.       If \Out_DLL And   \Out_Head\About   :  CallCFunctionFast(\Out_Head\About,  \WindowID)  :  EndIf
  664.    EndWith
  665.  
  666. EndProcedure
  667. ProcedureCDLL  Amp_OutConfig()
  668.  
  669.    If RS_AMPMASTER\IsOpen  =  #False   :  RETURN_ERR(#EAMP_NO_OUTDLL)   :  EndIf
  670.  
  671.    With  RS_WINAMP
  672.       If \Out_DLL And   \Out_Head\Config  :  CallCFunctionFast(\Out_Head\Config, \WindowID)  :  EndIf
  673.    EndWith
  674.  
  675. EndProcedure
  676.  
  677. ProcedureCDLL  Amp_InfoBox(*File)
  678.  
  679.    ; Shows in_dll depended informations
  680.  
  681.    If RS_AMPMASTER\IsOpen  =  #False   :  RETURN_ERR(#EAMP_NO_INDLL)    :  EndIf
  682.    If Amp_IsFile(*File)    =  #False   :  RETURN_ERR(#EAMP_OPEN_FILE)   :  EndIf
  683.  
  684.    With  RS_WINAMP
  685.       If \In2_DLL And   \In2_Head\InfoBox
  686.          ProcedureReturn   CallCFunctionFast(\In2_Head\InfoBox, *File, \WindowID)
  687.       EndIf
  688.    EndWith
  689.  
  690.    ProcedureReturn   #Null
  691.  
  692. EndProcedure
  693. ProcedureCDLL  Amp_GetFileInfo(*File, *Title, *Length)
  694.    ;************************************************
  695.    ; File   =  0 -> current played file
  696.    ; Title  =  Buffer{2048} for real title of module
  697.    ; Length =  Integer for time in ms
  698.    ;************************************************
  699.    If RS_AMPMASTER\IsOpen  =  #False   :  RETURN_ERR(#EAMP_NO_INDLL)    :  EndIf
  700.    If Amp_IsFile(*File)    =  #False   :  RETURN_ERR(#EAMP_OPEN_FILE)   :  EndIf
  701.  
  702.    With  RS_WINAMP
  703.       If \In2_DLL And   \In2_Head\GetFileInfo
  704.          CallCFunctionFast(\In2_Head\GetFileInfo, *File, *Title, *Length)
  705.       EndIf
  706.    EndWith
  707.  
  708. EndProcedure
  709.  
  710. ProcedureCDLL  Amp_SetDefaultLength(Milliseconds.i)
  711.    ;**************************************************************
  712.    ; Set default playlength if no calculated musiclength by in_dll
  713.    ; -------------------------------------------------------------
  714.    ; Milliseconds =  length in ms or default length (300000)
  715.    ;**************************************************************
  716.    With  RS_AMPMASTER
  717.  
  718.       If Milliseconds   <= #Null
  719.          Milliseconds   =  #DAMP_LENGTH
  720.       EndIf
  721.  
  722.       \DefaultLength =  Milliseconds
  723.  
  724.    EndWith
  725.  
  726. EndProcedure
  727. ProcedureCDLL  Amp_GetInFormatStr()
  728.  
  729.    ; Return supported tracker + (*.formats;..) by in_dll only (winamp)
  730.  
  731.    If RS_AMPMASTER\IsOpen  =  #False   :  RETURN_ERR(#EAMP_NO_INDLL) :  EndIf
  732.  
  733.    With  RS_AMPMASTER
  734.  
  735.       Protected   NewList  Srt.s()
  736.  
  737.       Protected   i, e$, i$
  738.       Protected   *Ptr.Character =  RS_WINAMP\In2_Head\FileExtensions
  739.  
  740.       If *Ptr
  741.  
  742.          \Formats$   =  #Null$   ; clear string
  743.  
  744.          While *Ptr\c
  745.  
  746.             e$ =  PeekS(*Ptr) :  *Ptr  +  Len(e$)  +  SizeOf(Character)
  747.             i$ =  PeekS(*Ptr) :  *Ptr  +  Len(i$)  +  SizeOf(Character)
  748.  
  749.             i  =  StrStrI_(i$, "(")
  750.  
  751.             AddElement(Srt())
  752.  
  753.             If i
  754.                CharLower_(i)  :  Srt() =  i$
  755.             Else
  756.                CharLower_(@e$):  Srt() =  i$ +  " ("  +  e$ +  ")"   ; eg. in_tfmx.dll
  757.             EndIf
  758.  
  759.          Wend
  760.  
  761.          SortList(Srt(), #PB_Sort_Ascending)
  762.  
  763.          ForEach  Srt()
  764.             \Formats$   +  Srt() +  #LF$
  765.          Next
  766.  
  767.          \Formats$   =  Trim(\Formats$, #LF$)
  768.  
  769.       Else
  770.  
  771.          \Formats$   =  #Empty$  ; must set empty$ coz error if null$
  772.  
  773.       EndIf
  774.  
  775.       FreeList(Srt())
  776.  
  777.       ProcedureReturn   @\Formats$
  778.  
  779.    EndWith
  780.  
  781. EndProcedure
  782.  
  783. ProcedureCDLL  Amp_SetAmpPath(*Path)
  784.  
  785.    ; Set path for in_/out_dll
  786.  
  787.    With  RS_AMPMASTER
  788.  
  789.       If *Path
  790.          \Path$   =  PeekS(*Path)
  791.       Else
  792.          \Path$   =  GetPathPart(\ProgramName$) +  #DAMP_PATH$
  793.       EndIf
  794.  
  795.       If Right(\Path$, 1)  <> "\"   :  \Path$   +  "\"   :  EndIf
  796.  
  797.       \InPath$    =  \Path$
  798.       \OutPath$   =  \Path$
  799.  
  800.    EndWith
  801.  
  802. EndProcedure
  803.  
  804. ProcedureCDLL  Amp_SetInPath(*Path)
  805.  
  806.    ; Set path for in_dll only
  807.  
  808.    With  RS_AMPMASTER
  809.       If *Path
  810.          \InPath$ =  PeekS(*Path)
  811.       Else
  812.          \InPath$ =  GetPathPart(\ProgramName$) +  #DAMP_PATH$
  813.       EndIf
  814.       If Right(\InPath$, 1)   <> "\"   :  \InPath$ +  "\"   :  EndIf
  815.    EndWith
  816.  
  817. EndProcedure
  818. ProcedureCDLL  Amp_SetInDll(*InLib)
  819.  
  820.    ; Set in_dll for musicfile
  821.  
  822.    With  RS_AMPMASTER
  823.       If *InLib
  824.          \InDll$  =  PeekS(*InLib)  :  If GetPathPart(\InDll$) :  \InPath$ =  GetPathPart(\InDll$) :  EndIf
  825.       EndIf
  826.    EndWith
  827.  
  828. EndProcedure
  829. ProcedureCDLL  Amp_SetOutPath(*Path)
  830.  
  831.    ; Set path to out_dll only
  832.  
  833.    With  RS_AMPMASTER
  834.       If *Path
  835.          \OutPath$   =  PeekS(*Path)
  836.       Else
  837.          \OutPath$   =  GetPathPart(\ProgramName$) +  #DAMP_PATH$
  838.       EndIf
  839.       If Right(\OutPath$, 1)  <> "\"   :  \OutPath$   +  "\"   :  EndIf
  840.    EndWith
  841.  
  842. EndProcedure
  843. ProcedureCDLL  Amp_SetOutDll(*OutLib)
  844.  
  845.    ; Set out_dll for musicplay
  846.  
  847.    With  RS_AMPMASTER
  848.       If *OutLib
  849.          \OutDll$ =  PeekS(*OutLib) :  If GetPathPart(\OutDll$)   :  \OutPath$   =  GetPathPart(\InDll$) :  EndIf
  850.       EndIf
  851.    EndWith
  852.  
  853. EndProcedure
  854. ProcedureCDLL  Amp_SetWindow(*Window)
  855.  
  856.    ; Set Window for callback
  857.  
  858.    With  RS_AMPMASTER
  859.       If *Window
  860.          \WindowID   =  *Window
  861.       Else
  862.          \WindowID   =  GetForegroundWindow_()
  863.       EndIf
  864.       RS_WINAMP\WindowID   =  \WindowID
  865.       ;SetActiveWindow_(\WindowID)
  866.    EndWith
  867.  
  868. EndProcedure
  869.  
  870. ProcedureCDLL  Amp_GetAmpInDllStr(*File)
  871.    ;**************************************************************************************
  872.    ; If no in_dll is given, Amp searchs for predefined in_dll by extension (*.MOD & MOD.*)
  873.    ; -------------------------------------------------------------------------------------
  874.    ; Return:   ptr to string of in_dll
  875.    ;**************************************************************************************
  876.    With  RS_AMPMASTER
  877.  
  878.       \InDll$  =  #Empty$
  879.  
  880.       If *File
  881.  
  882.          Protected   File$ =  GetFilePart(PeekS(*File))  ; No spaces allowed (extension can't use it)
  883.          Protected   i     =  CountString(File$, ".") +  1
  884.  
  885.          If i  >  1
  886.  
  887.             Protected   *i_x.RS_INTABLE   =  *i_n
  888.  
  889.             Protected   a$ =  ";"   +  Trim(StringField(File$, i, ".")) +  ";"   ; 1. try -> *.MOD (standard PC)
  890.             Protected   b$ =  ";"   +  Trim(StringField(File$, 1, ".")) +  ";"   ; 2. try -> MOD.* (classic Amiga)
  891.  
  892.             While *i_x\iFLG
  893.                If StrStrI_(@*i_x\iEXT\s, @a$)   Or StrStrI_(@*i_x\iEXT\s, @b$)
  894.                   \InDll$  =  *i_x\iLIB\s :  Break
  895.                EndIf
  896.                *i_x  +  SizeOf(RS_INTABLE)
  897.             Wend
  898.  
  899.          EndIf
  900.       EndIf
  901.  
  902.       ProcedureReturn   @\InDll$
  903.  
  904.    EndWith
  905.  
  906. EndProcedure
  907.  
  908. ProcedureCDLL  Amp_CountAmpFormatsAll()
  909.    ;*************************************************************
  910.    ; Calculates number of all supported formats (*.MOD) by AmpLib
  911.    ; ------------------------------------------------------------
  912.    ; Return: Number of all supported formats
  913.    ;*************************************************************
  914.    With  RS_AMPMASTER
  915.  
  916.       If \nAmpFormatsAll   :  ProcedureReturn   \nAmpFormatsAll   :  EndIf
  917.  
  918.       Protected   i, t$, e$
  919.       Protected   *i_x.RS_INTABLE   =  *i_n
  920.  
  921.       Protected   NewMap   Extensions.s()
  922.  
  923.       While *i_x\iFLG
  924.  
  925.          i  =  #Null
  926.  
  927.          t$ =  Trim(*i_x\iEXT\s, ";")
  928.  
  929.          Repeat
  930.             i  +  1  :  e$ =  StringField(t$, i, ";") :  Extensions(e$) +  1
  931.          Until Len(e$)  =  0
  932.  
  933.          *i_x  +  SizeOf(RS_INTABLE)   ; Next in Table-Ptr
  934.  
  935.       Wend
  936.  
  937.       \nAmpFormatsAll   =  MapSize(Extensions())   -  1  ; No/empty extension (-1)
  938.  
  939.       FreeMap(Extensions())
  940.  
  941.       ProcedureReturn   \nAmpFormatsAll
  942.  
  943.    EndWith
  944.  
  945. EndProcedure
  946. ProcedureCDLL  Amp_CountAmpPlayersAll()
  947.    ;****************************************************************
  948.    ; Calculates number of all supported players (in_*.dll) by AmpLib
  949.    ; ---------------------------------------------------------------
  950.    ; Return: Number of all supported players (in_dlls)
  951.    ;****************************************************************
  952.    With  RS_AMPMASTER
  953.  
  954.       If \nAmpPlayersAll   :  ProcedureReturn   \nAmpPlayersAll   :  EndIf
  955.  
  956.       Protected   *i_x.RS_INTABLE   =  *i_n
  957.  
  958.       While *i_x\iLIB\s
  959.  
  960.          \nAmpPlayersAll   +  1
  961.  
  962.          *i_x  +  SizeOf(RS_INTABLE)   ; Next in Table-Ptr
  963.  
  964.       Wend
  965.  
  966.       ProcedureReturn   \nAmpPlayersAll
  967.  
  968.    EndWith
  969.  
  970. EndProcedure
  971. ProcedureCDLL  Amp_GetAmpFormatsStrAll()
  972.    ;***********************************************************
  973.    ; Generates sorted string of all supported formats by AmpLib
  974.    ; ----------------------------------------------------------
  975.    ; Return: ptr to (very long) formatstring (*.A;*.B;*.C;...)
  976.    ;***********************************************************
  977.    With  RS_AMPMASTER
  978.  
  979.       If Len(\sAmpFormatsAll$)   :  ProcedureReturn   @\sAmpFormatsAll$ :  EndIf
  980.  
  981.       Protected   i, t$, e$
  982.       Protected   *i_x.RS_INTABLE   =  *i_n
  983.  
  984.       Protected   NewMap   Extensions.s()
  985.       Protected   NewList  Srt.s()
  986.  
  987.       While *i_x\iFLG
  988.  
  989.          i  =  #Null
  990.  
  991.          t$ =  Trim(*i_x\iEXT\s, ";")
  992.  
  993.          Repeat
  994.             i  +  1  :  e$ =  StringField(t$, i, ";") :  Extensions(e$) +  1
  995.          Until Len(e$)  =  0
  996.  
  997.          *i_x  +  SizeOf(RS_INTABLE)   ; Next in Table-Ptr
  998.  
  999.       Wend
  1000.  
  1001.       ForEach  Extensions()
  1002.          If MapKey(Extensions())
  1003.             AddElement(Srt()) :  Srt() =  MapKey(Extensions())
  1004.          EndIf
  1005.       Next
  1006.  
  1007.       SortList(Srt(), #PB_Sort_Ascending)
  1008.  
  1009.       ForEach  Srt()
  1010.          \sAmpFormatsAll$  +  ";*." +  Srt()
  1011.       Next
  1012.  
  1013.       CharLower_(@\sAmpFormatsAll$)
  1014.  
  1015.       FreeMap(Extensions())
  1016.       FreeList(Srt())
  1017.  
  1018.       ProcedureReturn   @\sAmpFormatsAll$
  1019.  
  1020.    EndWith
  1021. EndProcedure
  1022. ProcedureCDLL  Amp_GetAmpInDllsStrAll(*File)
  1023.    ;**************************************************************************************
  1024.    ; Generates sorted string of all predefined in_dlls used by extension
  1025.    ; -------------------------------------------------------------------------------------
  1026.    ; Return:   ptr to multi-string of in_dlls (in_xamp.dll;in_oldsk00l.dll;in_bass.dll...)
  1027.    ;**************************************************************************************
  1028.    With  RS_AMPMASTER
  1029.  
  1030.       \InDllsAll$ =  #Empty$
  1031.  
  1032.       If *File
  1033.  
  1034.          Protected   File$ =  GetFilePart(PeekS(*File))  ; No spaces allowed in PB (extensions can't use it)
  1035.          Protected   i     =  CountString(File$, ".") +  1
  1036.  
  1037.          If i  >  1
  1038.  
  1039.             Protected   *i_x.RS_INTABLE   =  *i_n
  1040.  
  1041.             Protected   a$ =  ";"   +  Trim(StringField(File$, i, ".")) +  ";"   ; 1. try -> *.MOD (standard PC)
  1042.             Protected   b$ =  ";"   +  Trim(StringField(File$, 1, ".")) +  ";"   ; 2. try -> MOD.* (classic Amiga)
  1043.  
  1044.             While *i_x\iFLG
  1045.                If StrStrI_(@*i_x\iEXT\s, @a$)   Or StrStrI_(@*i_x\iEXT\s, @b$)
  1046.                   \InDllsAll$ +  *i_x\iLIB\s +  ";"
  1047.                EndIf
  1048.                *i_x  +  SizeOf(RS_INTABLE)
  1049.             Wend
  1050.  
  1051.          EndIf
  1052.       EndIf
  1053.  
  1054.       ProcedureReturn   @\InDllsAll$
  1055.  
  1056.    EndWith
  1057.  
  1058. EndProcedure
  1059.  
  1060. ProcedureCDLL  Amp_GetErrorStr(Error.i)
  1061.  
  1062.    With  RS_AMPMASTER
  1063.  
  1064.       Select   Error
  1065.          Case  #EAMP_OK             :  \ErrorStr$  =  #SAMP_OK$
  1066.          Case  #EAMP_NO_INDLL       :  \ErrorStr$  =  #SAMP_NO_INDLL$
  1067.          Case  #EAMP_NO_OUTDLL      :  \ErrorStr$  =  #SAMP_NO_OUTDLL$
  1068.          Case  #EAMP_OPEN_FILE      :  \ErrorStr$  =  #SAMP_OPEN_FILE$
  1069.          Case  #EAMP_OPEN_INDLL     :  \ErrorStr$  =  #SAMP_OPEN_INDLL$
  1070.          Case  #EAMP_OPEN_OUTDLL    :  \ErrorStr$  =  #SAMP_OPEN_OUTDLL$
  1071.          Case  #EAMP_UNKOWN_FORMAT  :  \ErrorStr$  =  #SAMP_UNKOWN_FORMAT$
  1072.          Case  #EAMP_INITIALIZE     :  \ErrorStr$  =  #SAMP_INITIALIZE$
  1073.          Default
  1074.             \ErrorStr$  =  #SAMP_UNKNOWN$
  1075.       EndSelect
  1076.  
  1077.       ProcedureReturn   @\ErrorStr$
  1078.  
  1079.    EndWith
  1080.  
  1081. EndProcedure
  1082. ProcedureCDLL  Amp_GetError()
  1083.    ProcedureReturn   RS_AMPMASTER\ErrorN
  1084. EndProcedure
  1085.  
  1086. ProcedureCDLL  Amp_GetInInfoStr()
  1087.    ProcedureReturn   @RS_AMPMASTER\InInfo$
  1088. EndProcedure
  1089. ProcedureCDLL  Amp_GetOutInfoStr()
  1090.    ProcedureReturn   @RS_AMPMASTER\OutInfo$
  1091. EndProcedure
  1092.  
  1093. ;-
  1094. ;- *** Sub-Songs ***
  1095. ProcedureCDLL  Amp_SetSubSong(*File, SubSong.i)
  1096.    ;***************************************
  1097.    ; Set number of subsong to replay
  1098.    ; --------------------------------------
  1099.    ; *File:    @Ptr to full Path + Filename
  1100.    ; SubSong:  Number of subsong
  1101.    ; --------------------------------------
  1102.    ; Return:   #EAMP_OK if all ok
  1103.    ;***************************************
  1104.    With  RS_AMPMASTER
  1105.  
  1106.       If Amp_IsFile(*File) =  #False   :  RETURN_ERR(#EAMP_OPEN_FILE)   :  EndIf
  1107.       If SubSong  <= #Null :  SubSong  =  1  :  EndIf
  1108.  
  1109.       Protected   hF, i, TFM_OFFSET
  1110.       Protected   RS_PSID.RS_PSID
  1111.       Protected   RS_TFMX.RS_TFMX, *TFMX.RS_TFMX_AMP
  1112.  
  1113.       \SubSong =  SubSong
  1114.  
  1115.       hF =  OpenFile(#PB_Any, PeekS(*File))
  1116.       If hF
  1117.  
  1118.          \ID   =  ReadLong(hF)
  1119.  
  1120.          Select   \ID
  1121.  
  1122.             ; *** PSID
  1123.             Case  #ID_PSID
  1124.                FileSeek(hF, #Null)
  1125.                If ReadData(hF, @RS_PSID, SizeOf(RS_PSID))   =  SizeOf(RS_PSID)
  1126.                   \NumSongs   =  UINT16(RS_PSID\songs)
  1127.                   If \SubSong <= \NumSongs   And   \SubSong <> UINT16(RS_PSID\startSong)
  1128.                      FileSeek(hF,   OffsetOf(RS_PSID\startSong))
  1129.                      WriteWord(hF,  UINT16(\SubSong))
  1130.                      FlushFileBuffers(hF)
  1131.                   EndIf
  1132.                EndIf
  1133.  
  1134.             ; *** TFMX Hardcoded! Creates a not official TAG -> would be glad if another way to play subsongs in WinAMP!?
  1135.             Case  #ID_TFMX
  1136.  
  1137.                i  =  ReadLong(hF)
  1138.  
  1139.                Select   i
  1140.                   Case  #ID_SONG, #ID_2001, #ID_TMOD  ; Really TFMX-Song?
  1141.  
  1142.                      If i  =  #ID_TMOD :  TFM_OFFSET  =  $14   :  EndIf ; TFM -> Merged MDAT + SMPL?
  1143.  
  1144.                      FileSeek(hF, TFM_OFFSET)
  1145.  
  1146.                      If ReadData(hF, @RS_TFMX, SizeOf(RS_TFMX))   =  SizeOf(RS_TFMX)
  1147.  
  1148.                         *TFMX =  @RS_TFMX\StartPos -  SizeOf(RS_TFMX_AMP)
  1149.  
  1150.                         If *TFMX\ID =  #ID_AMP0 And   *TFMX\NumSongs >= \SubSong
  1151.  
  1152.                            \NumSongs   =  *TFMX\NumSongs
  1153.  
  1154.                            RS_TFMX\StartPos  [0]   =  *TFMX\StartPos ; Get/Restore SubSong[0] Start
  1155.                            RS_TFMX\EndPos    [0]   =  *TFMX\EndPos   ; Get/Restore SubSong[0] End
  1156.                            RS_TFMX\Tempo     [0]   =  *TFMX\Tempo    ; Get/Restore SubSong[0] Tempo
  1157.  
  1158.                            *TFMX\SubSong  =  \SubSong -  1  ; Set SubSong[n] as SubSong[0]
  1159.  
  1160.                            FileSeek(hF,   #TFMX_AMP_OFFSET  +  OffsetOf(RS_TFMX_AMP\SubSong) +  TFM_OFFSET) :  WriteByte(hF,  *TFMX\SubSong) ; Default SubSong
  1161.  
  1162.                            FileSeek(hF,   OffsetOf(RS_TFMX\StartPos) +  TFM_OFFSET) :  WriteData(hF,  @RS_TFMX\StartPos [*TFMX\SubSong],  SizeOf(Word))  ; $100
  1163.                            FileSeek(hF,   OffsetOf(RS_TFMX\EndPos)   +  TFM_OFFSET) :  WriteData(hF,  @RS_TFMX\EndPos   [*TFMX\SubSong],  SizeOf(Word))  ; $140
  1164.                            FileSeek(hF,   OffsetOf(RS_TFMX\Tempo)    +  TFM_OFFSET) :  WriteData(hF,  @RS_TFMX\Tempo    [*TFMX\SubSong],  SizeOf(Word))  ; $180
  1165.  
  1166.                         EndIf
  1167.                      EndIf
  1168.                EndSelect
  1169.  
  1170.             Case  #ID_FR10, #ID_FR12, #ID_FR4E, #ID_FR78 ; Really FRED Song? (*.fred)
  1171.                FileSeek(hF, $40)       ; Min. Offset
  1172.                For   i  =  0  To $80
  1173.                   If ReadWord(hF)&$FFFF   =  #ID_FRSS ; ID SubSongs?
  1174.                      \NumSongs   =  ReadByte(hF)   ; always $60 -> 6 Songs so we set it to 15 (#MAX_FRED)
  1175.                      \NumSongs   =  #MAX_FRED-1
  1176.                      \SubSong -  1
  1177.                      If \SubSong <= \NumSongs
  1178.                         \SubSong << 4  ; Nibblebyte to max. $F0
  1179.                         WriteByte(hF, \SubSong)
  1180.                      EndIf
  1181.                      Break
  1182.                   EndIf
  1183.                Next
  1184.  
  1185.             ; *** NSF
  1186.             Case  #ID_NESM
  1187.                If ReadWord(hF)   =  $011A
  1188.                   \NumSongs   =  ReadByte(hF)
  1189.                   If \SubSong <= \NumSongs
  1190.                      WriteByte(hF, \SubSong)
  1191.                   EndIf
  1192.                EndIf
  1193.  
  1194.             ; *** GBS
  1195.             Case  #ID_GBS1
  1196.                \NumSongs   =  ReadByte(hF)
  1197.                If \SubSong <= \NumSongs
  1198.                   WriteByte(hF, \SubSong)
  1199.                EndIf
  1200.  
  1201.          EndSelect
  1202.  
  1203.          CloseFile(hF)
  1204.       EndIf
  1205.  
  1206.    EndWith
  1207.  
  1208.    RETURN_ERR(#EAMP_OK)
  1209.  
  1210. EndProcedure
  1211. ProcedureCDLL  Amp_GetSubSong(*File)
  1212.    ;***************************************************************************
  1213.    ; Get actual subsong of format:  *.sid;*.mdat;*.tfm;*.tfx;*.nsf;*.gbs;*.fred
  1214.    ; --------------------------------------------------------------------------
  1215.    ; *File:    @Ptr to full Path + Filename
  1216.    ; --------------------------------------------------------------------------
  1217.    ; Return:   Number of actual subsong or < #NULL if error
  1218.    ;***************************************************************************
  1219.    With  RS_AMPMASTER
  1220.  
  1221.       If Amp_IsFile(*File) =  #False   :  RETURN_ERR(#EAMP_OPEN_FILE)   :  EndIf
  1222.  
  1223.       Protected   hF, i, TFM_OFFSET
  1224.  
  1225.       \SubSong =  #Null
  1226.  
  1227.       hF =  OpenFile(#PB_Any, PeekS(*File))
  1228.       If hF
  1229.  
  1230.          \ID   =  ReadLong(hF)
  1231.  
  1232.          Select   \ID
  1233.             Case  #ID_PSID ; *.sid
  1234.                FileSeek(hF, OffsetOf(RS_PSID\startSong))
  1235.                \SubSong =  ReadWord(hF)
  1236.                \SubSong =  UINT16(\SubSong)
  1237.  
  1238.             Case  #ID_TFMX ; mdat.*
  1239.  
  1240.                i  =  ReadLong(hF)
  1241.  
  1242.                Select   i
  1243.                   Case  #ID_SONG, #ID_2001, #ID_TMOD  ; Really TFMX-Song?
  1244.  
  1245.                      If i  =  #ID_TMOD :  TFM_OFFSET  =  $14   :  EndIf ; Merged MDAT + SMPL?
  1246.  
  1247.                      FileSeek(hF, #TFMX_AMP_OFFSET+TFM_OFFSET)
  1248.                      If ReadLong(hF)=  #ID_AMP0       ; You must! have called Amp_CountSubSongs() first (creates AMP0 tag)
  1249.                         \NumSongs   =  ReadByte(hF)
  1250.                         \SubSong    =  ReadByte(hF)   +  1
  1251.                      EndIf
  1252.                EndSelect
  1253.  
  1254.             Case  #ID_FR10, #ID_FR12, #ID_FR4E, #ID_FR78 ; Really FRED Song? (*.fred)
  1255.                FileSeek(hF, $40) ; Min. Offset
  1256.                For   i  =  0  To $80
  1257.                   If ReadWord(hF)&$FFFF   =  #ID_FRSS ; ID SubSongs?
  1258.                      \NumSongs   =  ReadByte(hF)
  1259.                      \SubSong    =  ReadByte(hF)   :  \SubSong    =  (\SubSong   >> 4) &  #MAX_FRED   +  1
  1260.                      Break
  1261.                   EndIf
  1262.                Next
  1263.  
  1264.             Case  #ID_NESM ; *.nsf
  1265.                If ReadWord(hF)=  $011A ; Really NSF-Song?
  1266.                   \NumSongs   =  ReadByte(hF)
  1267.                   \SubSong    =  ReadByte(hF)
  1268.                EndIf
  1269.  
  1270.             Case  #ID_GBS1 ; *.gbs
  1271.                \NumSongs   =  ReadByte(hF)
  1272.                \SubSong    =  ReadByte(hF)
  1273.  
  1274.          EndSelect
  1275.  
  1276.          CloseFile(hF)
  1277.       EndIf
  1278.  
  1279.       ProcedureReturn   \SubSong
  1280.  
  1281.    EndWith
  1282.  
  1283. EndProcedure
  1284. ProcedureCDLL  Amp_CountSubSongs(*File)
  1285.    ;******************************************************************
  1286.    ; Calculate subsongs of *.sid;*.mdat;*.tfm;*.tfx;*.nsf;*.gbs;*.fred
  1287.    ;******************************************************************
  1288.    With  RS_AMPMASTER
  1289.  
  1290.       If Amp_IsFile(*File) =  #False   :  RETURN_ERR(#EAMP_OPEN_FILE)   :  EndIf
  1291.  
  1292.       Protected   hF, i, TFM_OFFSET
  1293.       Protected   RS_TFMX.RS_TFMX
  1294.  
  1295.       \NumSongs   =  #Null
  1296.  
  1297.       hF =  OpenFile(#PB_Any, PeekS(*File))  ; read/write
  1298.       If hF
  1299.  
  1300.          \ID   =  ReadLong(hF)
  1301.  
  1302.          Select   \ID
  1303.             Case  #ID_PSID ; *.sid
  1304.                FileSeek(hF, OffsetOf(RS_PSID\songs))
  1305.                \NumSongs   =  ReadWord(hF)
  1306.                \NumSongs   =  UINT16(\NumSongs)
  1307.  
  1308.             Case  #ID_TFMX
  1309.  
  1310.                i  =  ReadLong(hF)
  1311.  
  1312.                Select   i
  1313.                   Case  #ID_SONG, #ID_2001, #ID_TMOD  ; Really TFMX (Custom) - Song? *.mdat(7), *.tfm, *.tfx
  1314.  
  1315.                      If i  =  #ID_TMOD :  TFM_OFFSET  =  $14   :  EndIf ; Skip merged MDAT + SMPL header of *.tfm?
  1316.  
  1317.                      FileSeek(hF, TFM_OFFSET)
  1318.  
  1319.                      If ReadData(hF, @RS_TFMX, SizeOf(RS_TFMX))   =  SizeOf(RS_TFMX)
  1320.  
  1321.                         FileSeek(hF, #TFMX_AMP_OFFSET+TFM_OFFSET)
  1322.  
  1323.                         If ReadLong(hF)   <> #ID_AMP0 ; Create AMP0 Tag?
  1324.  
  1325.                            \NumSongs   =  1  ; always 1 song!
  1326.  
  1327.                            For   i  =  1  To 31 ; Calculate real NumSongs[2..32]
  1328.                               If (RS_TFMX\StartPos[i] Or RS_TFMX\EndPos[i])   And   RS_TFMX\StartPos[i]<>$FF01 ; Code end of songs?
  1329.                                  If (RS_TFMX\StartPos[i-1]<>RS_TFMX\StartPos[i]  Or RS_TFMX\EndPos[i-1]<>RS_TFMX\EndPos[i])   ; no similar songs
  1330.                                     \NumSongs   +  1
  1331.                                  EndIf
  1332.                               EndIf
  1333.                            Next
  1334.  
  1335.                            FileSeek(hF,   #TFMX_AMP_OFFSET+TFM_OFFSET)  ; Hardcoded Tag RSET
  1336.  
  1337.                            ;i =  #ID_AMP0
  1338.                            WriteLong(hF,  #ID_AMP0)   ; ID-TAG
  1339.                            WriteByte(hF,  \NumSongs)  ; Number of avail songs (1-32)
  1340.  
  1341.                            ;i =  #Null
  1342.                            WriteByte(hF,  #Null)   ; Default SubSong[0-31] always NULL at first time
  1343.                            WriteData(hF,  @RS_TFMX\StartPos,SizeOf(Word))  ; Default StartSong[0]
  1344.                            WriteData(hF,  @RS_TFMX\EndPos,  SizeOf(Word))  ; Default EndSong[0]
  1345.                            WriteData(hF,  @RS_TFMX\Tempo,   SizeOf(Word))  ; Default Tempo[0]
  1346.  
  1347.                         Else  ; AMP0-Tag already exist!
  1348.                            \NumSongs   =  ReadByte(hF)
  1349.                            \SubSong    =  ReadByte(hF)
  1350.                         EndIf
  1351.  
  1352.                      EndIf
  1353.                EndSelect
  1354.  
  1355.             Case  #ID_FR10, #ID_FR12, #ID_FR4E, #ID_FR78 ; Really FRED Song? (*.fred)
  1356. ;              FileSeek(hF, $40)       ; Min. Offset
  1357. ;              For   i  =  0  To $80
  1358. ;                 If ReadWord(hF)&$FFFF   =  #ID_FRSS ; ID SubSongs?
  1359. ;                    \NumSongs   =  ReadByte(hF)
  1360. ;                    \NumSongs   =  UINT8(\NumSongs)  +  1
  1361. ;                    Break
  1362. ;                 EndIf
  1363. ;              Next
  1364.  
  1365.                ; *** NOTE:
  1366.                ; That is constant crap, but no info of variable header! There are not always
  1367.                ; subsongs, or/and wrong calculated by in_oldskool.dll!
  1368.                \NumSongs   =  #MAX_FRED   ; please check the songinfo
  1369.  
  1370.             Case  #ID_NESM
  1371.                If ReadWord(hF)   =  $011A
  1372.                   \NumSongs   =  ReadByte(hF)
  1373.                   \SubSong    =  ReadByte(hF)
  1374.                EndIf
  1375.  
  1376.             Case  #ID_GBS1
  1377.                \NumSongs   =  ReadByte(hF)
  1378.                \SubSong    =  ReadByte(hF)
  1379.  
  1380.          EndSelect
  1381.  
  1382.          CloseFile(hF)
  1383.       EndIf
  1384.  
  1385.       ProcedureReturn   \NumSongs
  1386.  
  1387.    EndWith
  1388.  
  1389. EndProcedure
  1390.  
  1391. ;-
  1392. ;- *** Intern time-handling ***
  1393. ProcedureCDLL  Amp_SetLength(Milliseconds.i)
  1394.    RS_AMPMASTER\MusicLength   =  Milliseconds
  1395. EndProcedure
  1396. ProcedureCDLL  Amp_GetPlayTime()
  1397.  
  1398.    ; return played time in ms
  1399.    With  RS_AMPTIME
  1400.  
  1401.       If RS_AMPMASTER\IsPlay
  1402.          \msPlay  =  MA_GetTime()   -  \msStart
  1403.       EndIf
  1404.  
  1405.       ProcedureReturn   \msPlay
  1406.  
  1407.    EndWith
  1408.  
  1409. EndProcedure
  1410. ProcedureCDLL  Amp_GetStopTime()
  1411.  
  1412.    ; return rest of time until stop
  1413.    With  RS_AMPTIME
  1414.  
  1415.       If RS_AMPMASTER\IsPlay
  1416.  
  1417.          \msStop  =  RS_AMPMASTER\MusicLength   -  (MA_GetTime()  -  \msStart)
  1418.  
  1419.          If \msStop  <  #Null
  1420.             \msStop  =  #Null
  1421.          EndIf
  1422.  
  1423.       EndIf
  1424.  
  1425.       ProcedureReturn   \msStop
  1426.  
  1427.    EndWith
  1428.  
  1429. EndProcedure
  1430. ProcedureCDLL  Amp_GetPercent()
  1431.  
  1432.    ; return percent of played time
  1433.    With  RS_AMPTIME
  1434.  
  1435.       If RS_AMPMASTER\IsPlay
  1436.  
  1437.          \msPercent  =  100.0 /  (RS_AMPMASTER\MusicLength * 0.001)  *  ((MA_GetTime() -  \msStart) * 0.001)
  1438.  
  1439.          If \msPercent  <  #Null
  1440.             \msPercent  =  #Null
  1441.          ElseIf   \msPercent  >  100
  1442.             \msPercent  =  100
  1443.          EndIf
  1444.  
  1445.       EndIf
  1446.  
  1447.       ProcedureReturn   \msPercent
  1448.  
  1449.    EndWith
  1450.  
  1451. EndProcedure
  1452.  
  1453. ;-
  1454. ;- *** Quick replay ***
  1455. ProcedureCDLL  Amp_Play(*File, Volume.i)
  1456.  
  1457.    With  RS_AMPMASTER
  1458.  
  1459.       Amp_Init()
  1460.  
  1461.       Amp_GetAmpInDllStr(*File)
  1462.       If Len(\InDll$)   =  #Null :  RETURN_ERR(#EAMP_NO_INDLL) :  EndIf
  1463.  
  1464.       Amp_SetAmpPath(0)
  1465.       SetCurrentDirectory(\Path$)
  1466.  
  1467.       If Amp_Open()  =  #EAMP_OK
  1468.          \Volume  =  Volume
  1469.          Amp_MusicPlay(*File)
  1470.       EndIf
  1471.  
  1472.       ProcedureReturn   \ErrorN
  1473.  
  1474.    EndWith
  1475.  
  1476. EndProcedure
  1477. ProcedureCDLL  Amp_QuickPlay(*File, *Path)
  1478.  
  1479.    ;If   Amp_IsFile(*File)    =  #False   :  RETURN_ERR(#EAMP_OPEN_FILE)   :  EndIf
  1480.  
  1481.    Protected   t$, RetVal
  1482.  
  1483.    With  RS_AMPMASTER
  1484.  
  1485.       Amp_Init()
  1486.  
  1487.       Amp_GetAmpInDllStr(*File)
  1488.       If Len(\InDll$)   =  #Null :  RETURN_ERR(#EAMP_NO_INDLL) :  EndIf
  1489.  
  1490.       Amp_SetAmpPath(*Path)
  1491.       SetCurrentDirectory(\Path$)
  1492.  
  1493.       If Amp_Open()  =  #EAMP_OK And   Amp_MusicPlay(*File) =  #EAMP_OK
  1494.  
  1495.          Amp_MusicSetVolume(#DAMP_VOLUME)
  1496.  
  1497.          t$ =  RSet(StrU((\MusicLength/(1000*60*60))),2, "0")  +  ":"   +  ; HH:
  1498.                RSet(StrU((\MusicLength/(1000*60))%60),2, "0")  +  ":"   +  ; MM:
  1499.                RSet(StrU((\MusicLength/1000)%60),     2, "0")              ; SS
  1500.  
  1501.          If (\MusicLength%1000)  ; ,TTT -> Rest milliseconds?
  1502.             t$ +  ","   +  RTrim(StrU(\MusicLength%1000), "0")
  1503.          EndIf
  1504.  
  1505.          t$ =  "File:"     +  #TAB$ +  GetFilePart(\MusicFile$)+  #CR$  +  #CR$  +
  1506.                "Plugin:"   +  #TAB$ +  GetFilePart(\InDll$)    +  #CR$  +
  1507.                               #TAB$ +  \InInfo$                +  #CR$  +  #CR$  +
  1508.                ;"Plugout:" +  #TAB$ +  GetFilePart(\OutDll$)   +  #CR$  +
  1509.                ;              #TAB$ +  \OutInfo$               +  #CR$  +  #CR$  +
  1510.                "Time:"     +  #TAB$ +  t$
  1511.       Else
  1512.          t$ =  PeekS(Amp_GetErrorStr(\ErrorN))
  1513.       EndIf
  1514.  
  1515.       Amp_VersionStr(0)
  1516.  
  1517.       MA_MsgBox(\WindowID, t$, \Version$)
  1518.  
  1519.       RetVal   =  \ErrorN
  1520.  
  1521.       Amp_Free()
  1522.  
  1523.       ProcedureReturn   RetVal
  1524.  
  1525.    EndWith
  1526.  
  1527. EndProcedure
  1528. ProcedureCDLL  Amp_MusicBox(*File, iFlags.i)
  1529.  
  1530.    Protected   t$, RetVal
  1531.  
  1532.    If *File :  t$ =  PeekS(*File)   :  EndIf
  1533.  
  1534.    RetVal   =  AmpPlayer::AmpBox(t$, iFlags)
  1535.  
  1536.    ProcedureReturn   RetVal
  1537.  
  1538. EndProcedure
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement