Advertisement
Testaware

AmpMaster DLL v1.18.11.15 (x86)

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