unit GenPlugServ;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses
  Windows, ComObj, ExtCtrls,
  CM2GenInterface, CM2EditorSupportInterface, CM2AutoUpdateInterface;

type
  TSong = Record
   title: ShortString;
   artist: ShortString;
   album: ShortString;
   year: ShortString;
   genre: ShortString;
   Filename: ShortString;
   bitrate: Word;
   samplingrate: Word;
   channelmode: shortString;
   positionINPercent: byte;
   songlength: shortString;
   Currenttime: shortString;
   rank: integer;
   playcount: integer;
   Status: shortString;
  end;
  TCM2GEN_WinAMP = class(TComObject, ICM2GenPlug, ICM2EditorSupport10, ICM2AutoUpdate)
    private
      dataTimer: TTimer;
      lastErrorString: pchar;
      firstRun: boolean;
      mp3Record: TSong;
      sharePointer: ^TSong;
      shareHandle: cardinal;
      fooStr: string;
      fooFlt: double;
      procedure ClearMP3Record;
      procedure OnTimer(Sender: TObject);
    protected
      // Declare Basics
      function Name(out Name: pchar): HResult; stdcall;
      function Version(out Version: word): HResult; stdcall;
      function RequiredCoreVersion(out RCV: word): HResult; stdcall;
      function SetParentHandle(Handle: THandle): HResult; stdcall;
      // Declare Error commands
      function GetLastErrorMsg(out Msg: pchar): HResult; stdcall;
      // Declare Info system
      function GetInfoCount(out InfoCount: integer): HResult; stdcall;
      function GetInfo(Index: integer; out InfoName: pchar; out InfoVar: pchar): HResult; stdcall;
      // Declare Sensor system
      function GetSensorCount(out SensorCount: integer): HResult; stdcall;
      function GetSensorNameOnly(Index: integer; out SensorName: pchar; out SensorStyle: byte): HResult; stdcall;
      function GetSensor(Index: integer; Parameters: pchar; out SensorName: pchar; out SensorStyle: byte; out SensorString: pchar; out SensorValue: double): HResult; stdcall;
      // Declare "Event" functions
      function Init: HResult; stdcall;
      function Terminating: HResult; stdcall;
      function Setup: HResult; stdcall;
      // Default (Required)
      function GetDefaultCount(SensorIndex: integer; out DefaultCount: integer): HResult; stdcall;
      function GetDefault(SensorIndex: integer; Index: integer; out Name: pchar; out Value: pchar; out Description: pchar): HResult; stdcall;
      // Optional
      function GetOptionalCount(SensorIndex: integer; out OptionalCount: integer): HResult; stdcall;
      function GetOptional(SensorIndex: integer; Index: integer; out Name: pchar; out Value: pchar; out Description: pchar): HResult; stdcall;
      function ShowSensor(Index: integer; out ShowAt: byte): HResult; stdcall;
      function ObjIns(SensorIndex: integer; ParameterName: pchar; out ValueType: byte; out ValueRange: pchar): HResult; stdcall;
      function UpdateFileURL(out URL: pchar): HResult; stdcall;
  end;

const
  Class_CM2GEN_WinAMP: TGUID = '{9327FE61-071A-45DA-B8AB-75E0BAF055D0}';
  UpdateURL: PChar = 'http://www.coolmon.org/update/winamp.upd';
  ReqCoreVersion: word = 0500;
  PlugInVersion: Word = 0210;
{
Change Log:
v 0200
 - removed the bulky shared memory component in favor of direct calls to the API
 - changed Do Show sensor, it should work better now
v 0101
 - fixed the many shared memory errors
v 0100
 - first test release.
}

implementation

uses ComServ;

{ TCM2GEN_WinAMP }

function TCM2GEN_WinAMP.Name(out Name: pchar): HResult;
begin
  result := S_OK;
  Name := 'WinAMP Info';
end;

function TCM2GEN_WinAMP.Version(out Version: word): HResult;
begin
  result := S_OK;
  Version := PlugInVersion;
end;

function TCM2GEN_WinAMP.RequiredCoreVersion(out RCV: word): HResult;
begin
  result := S_OK;
  RCV := ReqCoreVersion;
end;

function TCM2GEN_WinAMP.SetParentHandle(Handle: THandle): HResult;
begin
  result := S_OK;
end;

function TCM2GEN_WinAMP.GetLastErrorMsg(out Msg: pchar): HResult;
begin
  result := S_OK;
  if lastErrorString = '' then lastErrorString := 'No error';
  Msg := lastErrorString;
end;

function TCM2GEN_WinAMP.GetInfoCount(out InfoCount: integer): HResult;
begin
  result := S_OK;
  InfoCount := 4;
end;

function TCM2GEN_WinAMP.GetInfo(Index: integer; out InfoName, InfoVar: pchar): HResult;
begin
  result := S_OK;
  case Index of
   0: begin
        InfoName := 'Programmed By';
        InfoVar := 'blert & Aaangel';
      end;
   1: begin
        InfoName := 'Created';
        InfoVar := 'July 7th, 2004';
      end;
   2: begin
        InfoName := 'Updated';
        InfoVar := 'December 9th, 2004';
      end;
   3: begin
        InfoName := 'Copyright';
        InfoVar := '(c)2004 - The CoolMon Project';
      end;
   else begin
          result := E_FAIL;
          lastErrorString := 'Index out of bounds';
        end;
  end;
end;

function TCM2GEN_WinAMP.GetSensorCount(out SensorCount: integer): HResult;
begin
  result := S_OK;
  SensorCount := 16;
end;

function TCM2GEN_WinAMP.GetSensorNameOnly(Index: integer; out SensorName: pchar; out SensorStyle: byte): HResult;
begin
  result := S_OK;
  SensorStyle := 1;
  case Index of
    0: SensorName := 'Title';
    1: SensorName := 'Artist';
    2: SensorName := 'Album';
    3: SensorName := 'Year';
    4: SensorName := 'Genre';
    5: SensorName := 'Filename';
    6: begin
         SensorName := 'Bit Rate';
         SensorStyle := 0;
       end;
    7: begin
         SensorName := 'Sampling Rate';
         SensorStyle := 0;
       end;
    8: SensorName := 'Channel Mode';
    9: begin
         SensorName := 'Position Percent';
         SensorStyle := 0;
       end;
   10: SensorName := 'Length';
   11: SensorName := 'Current Time';
   12: SensorName := 'Status';
   13: SensorName := 'Do Show';
   14: SensorName := 'Ranking';
   15: SensorName := 'PlayCount';
   else begin
          result := E_FAIL;
          lastErrorString := 'Index out of bounds';
        end;
  end;
end;

function TCM2GEN_WinAMP.GetSensor(Index: integer; Parameters: pchar; out SensorName: pchar; out Sensorstyle: byte; out SensorString: pchar; out SensorValue: double): HResult;
begin
  result := S_OK;
  if firstRun then
    begin
      firstRun := false;
      ClearMP3Record;
      dataTimer := TTimer.Create(nil);
      dataTimer.OnTimer := OnTimer;
      dataTimer.Interval := 1000;
      dataTimer.Enabled := true;
      exit;
    end;
  fooStr := '';
  fooFlt := 0;
  SensorStyle := 1;
  case Index of
    0: begin
         SensorName := 'Title';
         fooStr := mp3Record.Title;
       end;
    1: begin
         SensorName := 'Artist';
         fooStr := mp3Record.Artist;
       end;
    2: begin
         SensorName := 'Album';
         fooStr := mp3Record.Album;
       end;
    3: begin
         SensorName := 'Year';
         fooStr := mp3Record.Year;
       end;
    4: begin
         SensorName := 'Genre';
         fooStr := mp3Record.Genre;
       end;
    5: begin
         SensorName := 'Filename';
         fooStr := mp3Record.Filename;
       end;
    6: begin
         SensorName := 'Bit Rate';
         SensorStyle := 0;
         fooFlt := mp3Record.BitRate;
       end;
    7: begin
         SensorName := 'Sampling Rate';
         SensorStyle := 0;
         fooFlt := mp3Record.SamplingRate;
       end;
    8: begin
         SensorName := 'Channel Mode';
         fooStr := mp3Record.ChannelMode;
       end;
    9: begin
         SensorName := 'Position Percent';
         SensorStyle := 0;
         fooFlt := mp3Record.PositionInPercent;
       end;
   10: begin
         SensorName := 'Length';
         fooStr := mp3Record.SongLength;
       end;
   11: begin
         SensorName := 'Current Time';
         fooStr := mp3Record.CurrentTime;
       end;
   12: begin
         SensorName := 'Status';
         fooStr := mp3Record.Status;
       end;
   13: begin
         SensorName := 'Do Show';
         fooStr := mp3Record.Status;
         if fooStr = 'Not Available' then fooStr := 'No'
           else fooStr := 'Yes';
       end;
   14: Begin
         SensorName := 'Ranking';
         SensorStyle := 0;
         fooFlt := mp3Record.rank;
       end;
   15: Begin
         SensorName := 'PlayCount';
         SensorStyle := 0;
         fooFlt := mp3Record.playcount;
       end;  
  else begin
         result := E_FAIL;
         lastErrorString := 'Index out of bounds';
       end;
  end;
  SensorString := PChar(fooStr);
  SensorValue := fooFlt;
end;

function TCM2GEN_WinAMP.Init: HResult;
begin
  result := S_OK;
  firstRun := true;
end;

function TCM2GEN_WinAMP.Terminating: HResult;
begin
  result := S_OK;
  try
    dataTimer.Enabled := false;
    Pointer(dataTimer) := nil;
    dataTimer.Free;
  except
  end;
  try CloseHandle(shareHandle); except end;
end;

function TCM2GEN_WinAMP.Setup: HResult;
begin
  result := E_NOTIMPL;
end;

function TCM2GEN_WinAMP.GetDefaultCount(SensorIndex: integer; out DefaultCount: integer): HResult;
begin
  result := S_OK;
  DefaultCount := 0;
end;

function TCM2GEN_WinAMP.GetDefault(SensorIndex, Index: integer; out Name, Value, Description: pchar): HResult;
begin
  result := S_OK;
end;

function TCM2GEN_WinAMP.GetOptionalCount(SensorIndex: integer; out OptionalCount: integer): HResult;
begin
  result := S_OK;
  OptionalCount := 0;
end;

function TCM2GEN_WinAMP.GetOptional(SensorIndex, Index: integer; out Name, Value, Description: pchar): HResult;
begin
  result := S_OK;
end;

Function TCM2GEN_WinAMP.ShowSensor(Index: integer; out ShowAt: byte): HResult; stdcall;
begin
  result := S_OK;
end;

Function TCM2GEN_WinAMP.ObjIns(SensorIndex: integer; ParameterName: pchar; out ValueType: byte; out ValueRange: pchar): HResult; stdcall;
begin
  result := S_OK;
end;

Function TCM2GEN_WinAMP.UpdateFileURL(out URL: pchar): HResult; stdcall;
begin
  result := S_OK;
  URL := UpdateURL;
end;

procedure TCM2GEN_WinAMP.ClearMP3Record;
begin
  with mp3Record do
    begin
      Title := ' ';
      Artist := ' ';
      Album := ' ';
      Year := ' ';
      Genre := ' ';
      Filename := ' ';
      BitRate := 0;
      SamplingRate := 0;
      ChannelMode := ' ';
      PositionInPercent := 0;
      SongLength := ' ';
      CurrentTime := ' ';
      rank := 0;
      playcount := 0;
      Status := 'Not Available';
    end;
end;

procedure TCM2GEN_WinAMP.OnTimer(Sender: TObject);
begin
  shareHandle := OpenFileMapping(FILE_MAP_READ, False, 'CM2_WA_GEN');
  if shareHandle <> 0 then
    begin
      sharePointer := MapViewOfFile(shareHandle, FILE_MAP_READ, 0, 0, 0);
      mp3Record := sharePointer^;
      UnMapViewOfFile(sharePointer);
      CloseHandle(shareHandle);
    end
  else ClearMP3Record;
end;

initialization
  TComObjectFactory.Create(ComServer, TCM2GEN_WinAMP, Class_CM2GEN_WinAMP,
    'CM2GEN_WinAMP', 'CM2 General Plugin - WinAMP', ciMultiInstance, tmApartment);
end.
