скачать примеры к статье (плагины + исходники на Delphi)
Работать с плеером Winamp мы научились в статье Управление Winamp. Теперь перейдем к разработке плагинов для него.
Плагины к Winamp бывают пяти видов:
- Input – плагины для проигрывания различных форматов;
- Output – для записи музыки в различных форматах;
- General Purpose – плагины общего назначения;
- DSP/Effect – для обработки звука;
- 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 берёт на себя, поэтому создавать плагины к этому популярнейшему плееру может даже человек, весьма далёкий от музыки. В следующий раз мы поговорим о плагинах общего назначения.