Ліричний Вінамп

 | 13.19

Мой Компьютер, №13 (517), 18.08.2008

Як усе починалося

Раніше я юзав Вінамп, причому на екрані він практично не з’являвся — для пошуку альбому я використовував Total Commander, щоб програти, тиснув Apps, P і ні про що не турбувався. Потім я побачив Windows Media Player 11, а точніше його бібліотеку з обкладинками альбомів, і вона так сподобалась, що я перейшов на WMP, незважаючи на його недоліки (не можна налаштувати гарячі клавіші, невмируща кнопка на таскбарі, не підтримує ogg vorbis (грати-то грає, але в бібліотеку не додає)). Можливо, це виправляється плагінами, але чому їх тоді нема в стандартній поставці? Та і бібліотека, буває, глючить.

Деякий час я з цим мирився, впорядковував свою колекцію пісень. Для повноти вирішив збирати тексти пісень. Оскільки з’явились вірші, то час від часу слухаючи пісні, я відкривав тексти й ознайомлювався з ними. Траплялось таке досить часто, тому скоро процес відкриття тексту поточної пісні набрид, захотілось його автоматизувати. На жаль, плеєрів з фічею перегляду тексту пісні, що програється, я не знаю (ідею написати свій я відклав на майбутнє :-), але ж можна апгрейдити існуючий. Я не про open-source, а про плагіни візуалізації, які немов створені були спеціально для моєї мети.

Коли з’явились в мене пісні в форматі ogg vorbis, я завітав на сайт Вінампу, в списку нововведень останньої версії побачив слова Album art, сказав, що Мікрософт маст дай, і поставив собі те, чим завжди користувався (себто Вінамп). Бібліотека в ньому таки відображає обкладинки альбомів, хоча і не так красиво, як у WMP. Зате можна писати вирази довільної складності для фільтрації бібліотеки, наприклад, всі пісні з високим бітрейтом (якщо хтось не зрозумів, я тут пишу про створення плагіну, а не про плеєри :-).

Враховуючи сказане вище (про Мікрософт), увечері я вже мав робочий плагін, а наступного дня довів його до стану, придатного до використання. Спочатку він просто відображав лірику, але оскільки з Делфі це реалізувати просто, то я додав налаштування шрифту, кольорів фону й тексту, а також можливість редагувати й зберігати текст.

Теорія

Перш за все знадобиться Winamp SDK (www.winamp.com). Цей архів на кількасот кілобайт містить в собі заголовочні файли і приклади плагінів. Документації там — кіт наплакав. Втім, не переймаймося цим, адже сурси прокоментовані (інгліш, звісно, але це ж не проблема, правда?). Мова C. Взагалі, для написання плагіну більш нічого й не потрібно. Беремо приклад і розбираємось. Але писати все, використовуючи Win32 API, досить незручно (про переваги й недоліки Win32 API поговоримо якось іншим разом).

Ні, якщо треба написати різнокольорові вогники, що стрибають в такт музиці, то проблем нема, беремо приклад плагіну, редагуємо функцію малювання вікна, і все. Але наша мета нестандартна. Для реалізації задуманого потрібні RichEdit, робота з кольорами, шрифтами, завантаження тексту з файлу та збереження. Тому Делфі знов стане в пригоді (дехто вважає, що Делфі — не мова програмування. Відкрийте Borland Help в BDS, там безліч разів зустрічається словосполучення Delphi Language). І саме про особливості написання плагіну візуалізації для Вінампу в Делфі я й розповім, оскільки у випадку С нічого, окрім перекладу Winamp SDK, не вийде. Плагін та сурси знаходяться на моєму сайті www.mahpella.com (щоправда сайт — гучно сказано).

Хоча розробники плеєру і пишуть, що він був спроектований для підтримки плагінів, написаних на C та C++, але ніяких труднощів нема, треба лише транслювати кілька структур, описати кілька констант і не забувати ставити cdecl.

Взагалі плагіни для Вінампу бувають кількох типів — вводу, виводу, візуалізації, DSP/ефекти, загального призначення, для бібліотеки та портативних пристроїв. Цікаво, що Вінамп розрізняє типи плагінів за іменем файлу, для кожного типу — свій префікс, файл плагіну візуалізації повинен називатись vis_*.dll.

Як воно працює. Плагін створює вікно, Вінамп з певним інтервалом викликає функцію Render, передаючи масив даних про поточний рівень звуку, функція перемальовує вікно.

Отже. Плагін візуалізації — це звичайнісінька DLL, що експортує одну-єдину функцію — winampVisGetHeader, яка повертає вказівник на структуру (нічого, що я вживатиму це слово замість дельфійського запису?) TWinampVisHeader. Ця структура містить назву плагіну, версію та вказівник на функцію, що повертатиме модулі, точніше вказівники на структури, що описують модулі. Створіть файл visheader.pas (аналог vis.h з Winamp SDK).

// Структура, що описує весь плагін.

TWinampVisHeader = packed record

 Version: Integer; // Версія. $101 = v1.01.

 Description: PChar; // Опис плагіну.

 GetModule: TGetModuleProc;

end;

// Вказівник на структуру TWinampVisHeader

PWinampVisHeader = ^TWinampVisHeader;

Бібліотека повинна мати глобальну змінну типу TWinampVisHeader, ініціалізувати її, а функція winampVisGetHeader — просто повернути вказівник на цю змінну. Для TWinampVisHeader потрібна функція GetModule. Що це за модулі такі? Якщо ви хочете реалізувати кілька алгоритмів візуалізації, то необов’язково створювати кілька плагінів, можна помістити все в один, при виборі плагіну візуалізації у Вінампі (Ctrl + K) користувач зможе вибрати потрібний модуль. Тобто можна сказати, що модуль — це і є плагін, мінімальна структурна одиниця, що розширює функціональність програми. Модуль описується структурою TWinampVisModule.

// Описує модуль плагіну.

TWinampVisModule = packed record

 // Опис модулю.

 Description: PChar;

 // Батьківське вікно (заповнює Вінамп).

 HwndParent: HWND;

 // Хендл нашої ДЛЛ (заповнює Вінамп).

 HDllInstance: Cardinal;

 // Частота дискретизації (заповнює Вінамп).

 SRate: Integer;

 // Кількість каналів (заповнює…).

 NCh: Integer;

 // Затримка від виклику RenderFrame до

 // малювання. Вінамп дивиться на це значення,

 // коли отримує дані.

 LatencyMs: Integer;

 // Затримка між малюваннями.

 DelayMs: Integer;

 // Дані про поточний рівень звуку.

 // Заповнюються відповідно

 // кількості каналів.

 SpectrumNch: Integer;

 WaveformNch: Integer;

 SpectrumData: array[1..2, 1..576] of byte;

 WaveformData: array[1..2, 1..576] of byte;

 // Діалог конфігурації.

 Config: TConfigProc;

 // Ініціалізація. Повернути 0 при успіху.

 Init: TInitProc;

 // Перемалювати вікно. Повернути 0 при успіху,

 // 1, якщо візуалізація повинна закінчитись.

 Render: TRenderProc;

 // Деініціалізація.

 Quit: TQuitProc;

 // Можна використати для зберігання

 // довільних даних.

 UserData: Pointer;

end;

// Вказівник на структуру TWinampVisModule.

PWinampVisModule = ^TWinampVisModule;

// Кілька процедурних типів.

TConfigProc = procedure(this_mod: PWinampVisModule); cdecl;

TInitProc = function(this_mod: PWinampVisModule): Integer; cdecl;

TRenderProc = function(this_mod: PWinampVisModule): Integer; cdecl;

TQuitProc = procedure(this_mod: PWinampVisModule); cdecl;

// Повернути модуль плагіну по номеру. Нумерація з нуля.

// Якщо модулів більш нема — nil. За допомогою цієї функції

// Вінамп отримує всі модулі плагіну.

TGetModuleProc = function(which: Integer): PWinampVisModule; cdecl;

Функція GetModule може мати такий вигляд:

function GetModule(which: Integer): PWinampVisModule; cdecl;

begin

 case which of

 0: Result := @module1;

 1: Result := @module2;

 2: Result := @module3;

 else Result := nil;

 end;

end;

// де module1, module2, module3 — глобальні // проініціалізовані змінні типу TWinampVisModule.

Кожен модуль характеризується зокрема чотирма функціями Config, Init, Render, Quit. Схема така: в Init створюємо вікно, в Quit знищуємо, в Render перемальовуємо, в Config показуємо діалог налаштувань.

Окрім того, ми можемо (і повинні, як пишуть розробники, хоча в противному випадку нічого поганого не відбудеться) опрацьовувати натиснення кнопок next, prev, random, fullscreen, за їх допомогою користувач змінює графічні образи (якщо їх декілька), вмикає чи вимикає їх довільний порядок, а також повноекранний режим.

Окрім цих двох структур, знадобляться константи для діалогу з Вінампом, які ви легко знайдете і транслюєте самі. Більшість знаходиться в wa_ipc.h.

Як бачите, нічого складного. Реалізацію функцій легко написати за допомогою Winamp SDK.

VCL + Winamp

Нема сенсу використовувати Делфі без VCL. Завдання інтеграції її компонент в програвач не з тривіальних. Вікна слід створювати конструктором CreateParented, якому треба передати хендл «embedded window» (термін з Winamp SDK). У відповідь на повідомлення WM_DESTROY компонент має викликати PostQuitMessage. Якщо ви створюєте простий контрол, а не вікно, то він має бути створений зі стилем WS_VISIBLE, інакше його не побачите. Глюки бувають. Спочатку я писав клас для відображення тексту на основі TMemo, так він не міняв колір шрифту, а фон змінювався лише біля країв вікна. А Memo.Lines.LoadFromFile викликав помилку. З TRichEdit все запрацювало як треба.

Я поміщав у Вінамп цілу форму з компонентами (цікаво виглядає). Для цього довелось написати обробник ще й для повідомлення WM_CLOSE, щоб надалі наша форма отримала WMDestroy.

procedure TForm1.WMClose(var Message: TWMClose);

begin

 DestroyWindow(Self.Handle);

end;

Справа в тому, що форма знищується при закритті, якщо це головна форма об’єкту Application, що в нашому випадку невірно. У відповідь на WM_CLOSE форма викликає метод Close.

procedure TCustomForm.Close;

var

 CloseAction: TCloseAction;

begin

 // Наша форма не модальна.

 if fsModal in FFormState then

 ModalResult := mrCancel

 else

 if CloseQuery then

 begin

   // І не MDI.

   if FormStyle = fsMDIChild then

   if biMinimize in BorderIcons then

    CloseAction := caMinimize else

    CloseAction := caNone

   else

   CloseAction := caHide;

   DoClose(CloseAction);

   if CloseAction <> caNone then

   // Ось той рядок. В нашому випадку він

   // не виконується.

   if Application.MainForm = Self then Application.Terminate

   // і форма просто ховається.

   else if CloseAction = caHide then Hide

   else if CloseAction = caMinimize then WindowState := wsMinimized

   else Release;

 end;

end;

Форма додається до проекту як звичайно (File>New>Form), створюється в функції Init модуля плагіну як і інші компоненти конструктором CreateParented. Тільки стиль форми BorderStyle поставте в bsNone, а то виглядатиме безглуздо.

Наостанок

Ось і все. Результат роботи представлений на рисунку.

Рис. 1

Якщо налаштувати кольори, то виглядає так, немов завжди там і було. Проблеми може викликати лише смуга прокрутки — її колір залежить від стилю Windows і може не гармонувати зі скіном програвача.

Я ще замислювався над реалізацією автоматичної прокрутки тексту, якщо він не вміщається весь. Але автоматизувати цей процес навряд чи вдасться. Є пісні, в першій половині яких слова відсутні, а є навпаки.

А ще треба б реалізувати автоматичне завантаження пісень з Інтернету. Якось я писав програму, що парсила веб-сторінки (з сайту DarkLyrics з текстами пісень одного альбому), створювала файли по одному на кожну пісню з їх текстами. В принципі, можна й так. Але такий підхід годиться для програмістів, для яких критерій якості тільки один — програма працює. На сайті AllCDCovers (на якому знаходиться вгадайте що) я бачив інтригуючі написи про розробників і нове API. Тобто програми можуть звертатись до цього сайту, щоб закачати обкладинки. Залишилось знайти аналогічне для сайтів з лірикою — і Lyrics v1.1 не за горами.

Ярик УЛАНОВИЧ aka Mahpella

Robo User
Web-droid editor

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *