{Winamp-like - base class}
unit winampapi;
{$include compilers.inc}

interface

uses windows,messages;

const
  WinampClass = 'Winamp v1.x';
  WinampTail  = ' - Winamp';

function WinampGetStatus(wnd:HWND):integer;
function WinampGetWindowText(wnd:HWND):pWideChar;
function WinampFindWindow(wnd:HWND):HWND;
function WinampCommand(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
function WinampGetInfo(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;

const
  WM_WA_IPC = WM_USER;
  IPC_GETVERSION       = 0;
  IPC_ISPLAYING        = 104;
  IPC_GETINFO          = 126;
  IPC_GETOUTPUTTIME    = 105;
  IPC_WRITEPLAYLIST    = 120;
  IPC_GETLISTLENGTH    = 124;
  IPC_GETLISTPOS       = 125;
  IPC_ISFULLSTOP       = 400; //!!
  IPC_INETAVAILABLE    = 242; //!!
  IPC_GETPLAYLISTFILE  = 211;

  IPC_IS_PLAYING_VIDEO = 501;

  IPC_PLAYFILE    = 100;
  IPC_STARTPLAY   = 102;
  IPC_SETVOLUME   = 122; // -666 returns the current volume.
  IPC_GET_SHUFFLE = 250;
  IPC_SET_SHUFFLE = 252;
  IPC_JUMPTOTIME  = 106;

const
  WINAMP_PREV       = 40044;
  WINAMP_PLAY       = 40045;
  WINAMP_PAUSE      = 40046;
  WINAMP_STOP       = 40047;
  WINAMP_NEXT       = 40048;
  WINAMP_VOLUMEUP   = 40058; // turns the volume up a little
  WINAMP_VOLUMEDOWN = 40059; // turns the volume down a little

implementation

uses common,wat_api;

function WinampFindWindow(wnd:HWND):HWND;
var
  pr,pr1:dword;
begin
  GetWindowThreadProcessId(wnd,@pr);
  result:=0;
  repeat
    result:=FindWindowEx(0,result,WinampClass,nil);
    if result<>0 then
    begin
      GetWindowThreadProcessId(result,@pr1);
      if pr=pr1 then
        break;
    end
    else
      break;
  until false;
end;

// ----------- Get player info ------------

function GetVersion(wnd:HWND):integer;
begin
  result:=SendMessage(wnd,WM_WA_IPC,0,IPC_GETVERSION);
end;

function GetVersionText(wnd:HWND):pWideChar;
var
  ver:integer;
  s:array [0..31] of WideChar;
  p:pWideChar;
begin
  ver:=GetVersion(wnd);
  p:=@s;
  IntToStr(p,ver shr 12);
  while p^<>#0 do inc(p);
  p^:='.';
  IntToStr(p+1,(ver shr 4) and $F);
  while p^<>#0 do inc(p);
  p^:='.';
  IntToStr(p+1,ver and $F);
  StrDupW(result,PWideChar(@s));
end;

function WinampGetStatus(wnd:HWND):integer;
begin
  result:=SendMessage(wnd,WM_WA_IPC,0,IPC_ISPLAYING);
  // 0 - stopped, 1 - playing
  if result>1 then
    result:=WAT_MES_PAUSED;
{
  if result=0 then // !! only for remote media!
  begin
    result:=SendMessage(wnd,WM_WA_IPC,0,IPC_ISFULLSTOP);
    if result<>0 then
      result:=WAT_MES_STOPPED
    else
      result:=WAT_MES_PLAYING;
  end;
}
end;

function WinampGetWindowText(wnd:HWND):pWideChar;
var
  a:cardinal;
  pc:pWideChar;
begin
  a:=GetWindowTextLengthW(wnd);
  mGetMem(result,(a+1)*SizeOf(WideChar));
  if GetWindowTextW(wnd,result,a+1)>0 then
  begin
    pc:=StrPosW(result,WinampTail);
    if pc<>nil then
    begin
      pc^:=#0;
      pc:=StrPosW(result,'. ');
      if pc<>nil then
        StrCopyW(result,pc+2);
    end;
  end;
end;

// --------- Get file info ----------

function GetKbps(wnd:HWND):integer;
begin
  result:=SendMessage(wnd,WM_WA_IPC,1,IPC_GETINFO);
  if result>1000 then
    result:=result div 1000;
end;

function GetKhz(wnd:HWND):integer;
begin
  result:=SendMessage(wnd,WM_WA_IPC,0,IPC_GETINFO);
  if result>1000 then
    result:=result div 1000;
end;

function GetChannels(wnd:HWND):integer;
begin
  result:=SendMessage(wnd,WM_WA_IPC,2,IPC_GETINFO);
end;

function GetTotalTime(wnd:HWND):integer;
begin
  result:=SendMessage(wnd,WM_WA_IPC,1,IPC_GETOUTPUTTIME);
end;

function GetElapsedTime(wnd:HWND):integer;
begin
  result:=SendMessage(wnd,WM_WA_IPC,0,IPC_GETOUTPUTTIME) div 1000;
end;

function GetVolume(wnd:HWND):integer;
begin
  result:=SendMessage(wnd,WM_WA_IPC,-666,IPC_SETVOLUME);
  result:=(result shl 16)+(result shr 4);
end;

function WinampGetInfo(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
var
  wnd:HWND;
begin
  result:=0;
  with pSongInfo(wParam)^ do
  begin
    if winampwnd<>0 then
      wnd:=winampwnd
    else
      wnd:=plwnd;

    if (lParam and WAT_OPT_PLAYERDATA)<>0 then
    begin
      if plyver=0 then
      begin
        plyver:=GetVersion(wnd);
        txtver:=GetVersionText(wnd);
      end;
    end
    else if (lParam and WAT_OPT_CHANGES)<>0 then
    begin
      volume:=GetVolume(wnd);
      if status<>WAT_MES_STOPPED then
        time:=GetElapsedTime(wnd);
//      wndtext:=WinampGetWindowText(wnd);
    end
    else
    begin
      if kbps    =0 then kbps    :=GetKbps(wnd);
      if khz     =0 then khz     :=GetKhz(wnd);
      if channels=0 then channels:=GetChannels(wnd);
      if total   =0 then total   :=GetTotalTime(wnd);
    end;
  end;
end;

// ------- Commands ----------

function Play(wnd:HWND):integer;
begin
  result:=SendMessage(wnd,WM_COMMAND,WINAMP_PLAY,0);
end;

function Pause(wnd:HWND):integer;
begin
  result:=SendMessage(wnd,WM_COMMAND,WINAMP_PAUSE,0);
end;

function Stop(wnd:HWND):integer;
begin
  result:=SendMessage(wnd,WM_COMMAND,WINAMP_STOP,0);
end;

function Next(wnd:HWND):integer;
begin
  result:=SendMessage(wnd,WM_COMMAND,WINAMP_NEXT,0);
end;

function Prev(wnd:HWND):integer;
begin
  result:=SendMessage(wnd,WM_COMMAND,WINAMP_PREV,0);
end;

function VolDn(wnd:HWND):integer;
begin
  result:=SendMessage(wnd,WM_COMMAND,WINAMP_VOLUMEDOWN,0);
end;

function VolUp(wnd:HWND):integer;
begin
  result:=SendMessage(wnd,WM_COMMAND,WINAMP_VOLUMEUP,0);
end;

procedure SetVolume(wnd:HWND;value:cardinal);
begin
  SendMessage(wnd,WM_WA_IPC,value shl 4,IPC_SETVOLUME);
end;

function Seek(wnd:HWND;value:integer):integer;
begin
  result:=SendMessage(wnd,WM_WA_IPC,0,IPC_GETOUTPUTTIME) div 1000;
    SendMessage(wnd,WM_WA_IPC,value*1000,IPC_JUMPTOTIME);
end;

function WinampCommand(wParam:WPARAM;lParam:LPARAM):int_ptr;cdecl;
var
  wnd:HWND;
begin
  wnd:=wParam;
  case LoWord(lParam) of
    WAT_CTRL_PREV : result:=Prev (wnd);
    WAT_CTRL_PLAY : result:=Play (wnd);
    WAT_CTRL_PAUSE: result:=Pause(wnd);
    WAT_CTRL_STOP : result:=Stop (wnd);
    WAT_CTRL_NEXT : result:=Next (wnd);
    WAT_CTRL_VOLDN: result:=VolDn(wnd);
    WAT_CTRL_VOLUP: result:=VolUp(wnd);
    WAT_CTRL_SEEK : result:=Seek (wnd,lParam shr 16);
  else
    result:=0;
  end;
end;

end.