Программирование на Delphi и не только » Архив блога Сделай сам на Delphi: Визуализационный плагин к Winamp | Программирование на Delphi и не только

скачать примеры  к статье (плагины + исходники на Delphi)

Работать с плеером Winamp мы научились в статье Управление Winamp. Теперь перейдем к разработке плагинов для него.
Плагины к Winamp бывают пяти видов:

  1. Input – плагины для проигрывания различных форматов;
  2. Output – для записи музыки в различных форматах;
  3. General Purpose – плагины общего назначения;
  4. DSP/Effect – для обработки звука;
  5. Visualization – плагины, которые делают что-нибудь в такт музыке.

Плагин к Winamp представляет из себя обычную динамическую библиотеку (DLL – Dynamic Link Library), которая должна экспортировать необходимую для данного плагина информацию. Шаблон библиотеки для любого типа плагинов можно взять на сайте Winamp’a – http://www.winamp.com. В этой статье мы рассмотрим процесс создания самого впечатляющего, на мой взгляд, типа плагинов – визуализационного.
В составе визуализационного плагина можно выделить заголовок и модули. Вот формат этих частей:

Заголовок плагина
winampVisHeader = packed record   version: Integer;   description: PChar;

  getModule: function( which: integer ): PwinampVisModule; cdecl;


end;

version – версия, для данного типа плагинов должна быть равна $101 (знак ‘$’ указывает на шестнадцатеричную систему счисления).
description – описание плагина.
getModule – функция, которая должна возвратить указатель на тело плагина.

Модуль плагина
winampVisModule = packed record
  //описание модуля   description: PChar;

  //идентификатор окна Winamp'a (заполняет Winamp)

  hwndParent: HWND;

  // идентификатор библиотеки (заполняет Winamp)

  hDllInstance: HWND;

  //sample rate (заполняет Winamp)

  sRate: Integer;

  //количество каналов (заполняет Winamp)

  nCh: Integer;

  //задержка между получением данных от Winamp'a и
  //реакцией на них (в мс)

  latencyMs: Integer;

  //количество мс между получениями данных от Winamp'a

  delayMs: Integer;

  //следующие 4 параметра и есть те данные о звуке, которые мы
  //будем через некоторый промежуток времени получать от Winamp'a

  spectrumNch: Integer;   waveformNch: Integer;

  spectrumData: array[0..1, 0..575] of byte;


  waveformData: array[0..1, 0..575] of byte;
  //процедура, которая будет вызываться при нажатии на кнопку "Конфигурация"
  Config: procedure( thismod: PwinampVisModule ); cdecl;
  //функция, вызываемая при инициализации плагина, должна возвратить 0, если всё в порядке
  Init: function( thismod: PwinampVisModule ): integer; cdecl;
  //функция, вызываемая при получении очередной порции данных   //от Winamp'a, именно здесь нужно реагировать на изменение   //музыкальных данных, должна возвратить 0, если всё в порядке,

  // или 1, если плагин завершает свою работу


  Render: function( thismod: PwinampVisModule ): Integer; cdecl;
  //процедура, вызываемая при завершении работы плагина
  Quit: procedure( thismod: PwinampVisModule ); cdecl;
  //здесь можно хранить указатель на свои данные   userData: pointer;

end;

Ну а теперь сделаем простой и абсолютно бесполезный визуализационный плагин, маленький анализатор спектра. Создайте в Delphi DLL. После этого создайте форму и положите на неё шесть компонентов TProgressBar, для которых свойство Orientation установите в положение pbVertical, а Max – в 300. Пример расположения компонент можете посмотреть на рис.1.

Всё, форму можно больше не трогать, займёмся теперь DLL. Вот код библиотеки:

library vis_MyFirstPlug;
uses   Windows, forms,   Unit1 in 'Unit1.pas' {Form1};

const


  //версия   VIS_HDRVER = $101;

  //класс окна

  szAppName = 'OurPlug';

  //описание плагина

  descr = 'Мой первый VIS плагин';

  //описание модуля

  mod1_descr = 'А это единственный модуль моего плагина';

type


  //типы заголовка и тела плагина   PwinampVisModule = ^winampVisModule;   winampVisModule = packed record   description: PChar;   hwndParent: HWND;   hDllInstance: HWND;   sRate: integer;   nCh: integer;   latencyMs: integer;   delayMs: integer;   spectrumNch: integer;   waveformNch: integer;   spectrumData: array[0..1,0..575] of byte;   waveformData: array[0..1,0..575] of byte;   Config: procedure(thismod: PwinampVisModule);cdecl;   Init: function(thismod: PwinampVisModule): integer;cdecl;   Render: function(thismod: PwinampVisModule): integer;cdecl;   Quit: procedure(thismod: PwinampVisModule);cdecl;   userData: pointer;

end;

PwinampVisHeader = ^winampVisHeader;

winampVisHeader = packed record

  version: integer;   description: PChar;

  getModule: function( which : integer ) : PwinampVisModule; cdecl;


end;
var
  //заголовок плагина   hdr: winampVisHeader;

  //модуль плагина


  mod1: winampVisModule;

//далее следуют процедуры, назначение которых описано выше
function getModule(which: integer): PwinampVisModule;cdecl;
begin
  case which of     0: result := @mod1;

    else


      result := nil
  end;
end;

function winampVisGetHeader: PwinampVisHeader; cdecl;
begin   result := @hdr;

end;

procedure config(this_mod: PwinampVisModule); cdecl;
begin   MessageBox(mod1.hwndParent, 'Настроек нет', 'Окно настроек', mb_OK);

end;

function init(this_mod: PwinampVisModule): integer; cdecl;
begin
  //показываем форму с ProgressBar'ами   Form1.Show;   result := 0;

end;

function render(this_mod: PwinampVisModule): integer; cdecl;
begin
  //при поступлении новых данных от Winamp'a устанавливаем   //высоту столбиков ProgressBar'ов в соответствии со значением

  //музыкальных данных шести колонок

  Form1.ProgressBar1.Position := this_mod.spectrumData[0,1];   Form1.ProgressBar2.Position := this_mod.spectrumData[0,2];   Form1.ProgressBar3.Position := this_mod.spectrumData[0,3];   Form1.ProgressBar4.Position := this_mod.spectrumData[0,4];   Form1.ProgressBar5.Position := this_mod.spectrumData[0,5];   Form1.ProgressBar6.Position := this_mod.spectrumData[0,6];   result := 0;

end;

procedure quit(this_mod: PwinampVisModule); cdecl;
begin
end;

//экспортируемая функция
exports
  winampVisGetHeader;
begin
  //заполняем начальные параметры плагина
  hdr.version := VIS_HDRVER;   hdr.description := PChar(descr);   hdr.getModule := @getModule;   mod1.description := PChar(mod1_descr);   mod1.hwndParent := 0;   mod1.hDllInstance := 0;   mod1.sRate := 0;   mod1.nCh := 0;   mod1.latencyMs := 25;   mod1.delayMs := 100;   mod1.spectrumNch := 2;   mod1.waveformNch := 0;   mod1.Config := @config;   mod1.Init := @init;   mod1.Render := @render;   mod1.Quit := @quit;

  //создаём форму с ProgressBar'ами

  Application.CreateForm(TForm1, Form1);

end.

Полученный плагин нужно скопировать в папку Winamp\Plugins. После этого в окне свойств Winamp’a будет доступен новый плагин (рис.2).

 

Этот пример призван продемонстрировать, как использовать всю мощь VCL в Delphi при создании плагинов для Winamp’a. Но размер такого плагина будет в районе 300-400 кб (зависит от версии Delphi). В связи с этим, лучше отказаться от использования VCL, а писать плагины на WinApi. Далее приведён код плагина, который заставляет мигать лампочки на клавиатуре (Num Lock, Caps Lock и Scroll Lock) в такт музыке.

library KeybLight;
uses Windows;
const   VIS_HDRVER = $101;   szAppName = 'KeybLight';   descr = 'Лампочки на клавиатуре (delphiblog.ru)';
  //описание плагина   mod1_descr = 'Лампочки на клавиатуре';

type


  //указатель на структуру плагина   PwinampVisModule = ^winampVisModule;

  //структура плагина


  winampVisModule = packed record     description: PChar;     hwndParent: HWND;     hDllInstance: HWND;     sRate: Integer;     nCh: Integer;     latencyMs: Integer;     delayMs: Integer;     spectrumNch: Integer;     waveformNch: Integer;

    spectrumData: array[0..1, 0..575] of Byte;


    waveformData: array[0..1, 0..575] of Byte;
    Config: procedure( thismod: PwinampVisModule ); cdecl;
    Init: function( thismod: PwinampVisModule ): Integer; cdecl;
    Render: function( thismod: PwinampVisModule ): Integer; cdecl;
    Quit: procedure( thismod: PwinampVisModule ); cdecl;     userData: pointer;

  end;


  //заголовок плагина
  PwinampVisHeader = ^winampVisHeader;
  winampVisHeader = packed record     version: Integer;     description: PChar;

    getModule: function( which: integer ): PwinampVisModule; cdecl;


  end;
var   hdr: winampVisHeader;

  mod1: winampVisModule;

//процедура для установки состояния клавиш Caps, Num, Scroll Lock
procedure SetLock(N: Byte; State: Boolean);
var   KeyState: TKeyboardState;   c: Byte;

begin


  case N of     0: c := VK_NUMLOCK;     1: c := VK_CAPITAL;     2: c := VK_SCROLL;

  end;

  GetKeyboardState(KeyState);

  if (State and (not((KeyState[c] and 1) = 1)) or ((not State) and ((KeyState[c] and 1) = 1))) then


    //key press
    keybd_event(c, $45, (KEYEVENTF_EXTENDEDKEY or 0), 0);
    //key release
    keybd_event( c, $45, (KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP), 0);
  end;

//возвращает указатель на нужный модуль
function getModule(which: integer): PwinampVisModule; cdecl;
begin
  case which of     0: result := @mod1;

    else result := nil


  end;
end;

//передача заголовка плагина Winamp'у
function winampVisGetHeader: PwinampVisHeader; cdecl;
begin   result := @hdr;

end;

//эта процедура вызывается при нажатии на кнопку "Конфигурация"
procedure config( this_mod: PwinampVisModule ); cdecl;
begin
  MessageBox(this_mod.hwndParent, 'Автор Иван Ширко (ishyrko@gmail.com)'+#13+' http://delphiblog.ru', 'Лампочки на клавиатуре', MB_OK)
end;

//инициализация плагина, если всё нормально, то должны вернуть 0
function init( this_mod: PwinampVisModule ): integer; cdecl;
begin   result:=0;

end;

//именно эта функция заставляет лампочки мигать
function render(this_mod: PwinampVisModule): integer; cdecl;
begin
  //в зависимости от уровня звука гасим\зажигаем   //соответствующие лампочки
  if (this_mod.spectrumData[0,1] > 40) then     SetLock(0, True)

  else

    SetLock(0, False);

  if (this_mod.spectrumData[0,5] > 40) then

    SetLock(1, True)

  else

    SetLock(1, False);

  if (this_mod.spectrumData[0,10] > 40) then

    SetLock(2, True)

  else

    SetLock(2, False);   result := 0;

end;

//наши действия при закрытии плагина
procedure quit( this_mod: PwinampVisModule ); cdecl;
begin
end;

//экспортируемая функция
exports
  winampVisGetHeader;
begin
  //задаём начальные значения для структуры плагина   hdr.version := VIS_HDRVER;   hdr.description := PChar(descr);   hdr.getModule := @getModule;   mod1.description := PChar(mod1_descr);   mod1.hwndParent := 0;   mod1.hDllInstance := 0;   mod1.sRate := 0;   mod1.nCh := 0;   mod1.latencyMs := 25;   mod1.delayMs := 25;   mod1.spectrumNch := 2;   mod1.waveformNch := 0;   mod1.Config := @config;   mod1.Init := @init;   mod1.Render := @render;   mod1.Quit := @quit;

end.

После компиляции в Delphi такой плагин занимает менее 20 килобайт! Готовую библиотеку и исходные тексты можно найти на форуме. К сожалению, мне не удалось найти вариант зажигания лампочек под WinXP без изменения состояния клавиш, так что печатать при включенном таком плагине будет проблематично. Но в качестве примера сгодится:)

Как видите, всю работу по обработке звука Winamp берёт на себя, поэтому создавать плагины к этому популярнейшему плееру может даже человек, весьма далёкий от музыки. В следующий раз мы поговорим о плагинах общего назначения.