AIMP Forum

AIMP for Windows => Дополнения / Addons => Разработка / Development => Topic started by: HardWareMan on March 07, 2008, 09:42:35

Title: Тонкости создания визуального плагина
Post by: HardWareMan on March 07, 2008, 09:42:35
Появилось время и я захотел доработать свой визуальный плагин LumaVU. Собственно, он работает, просто из-за постоянной перерисовки заднего фона он иногда мерцает. Пытаюсь решить эту проблему. Попробовал подключить 2 поверхность, рисовать в ней а потом зараз копировать готовое изображение в главный холст. Но что-то не получается. Ну или как вариант залочить канвас на время отрисовки...

Собственна, имею следующие вопросы:
1. Можно ли подключить дополнительные поверхности для уменьшения лишних перерисовок? Если да, то как?
2. Есть ли метод или функция, однозначно лочившая главный холст?

Так же интересно, как сам плеер считывает данные с холста для отрисовки или отрисовка происходит в холст плеера напрямую?
Title: Re: Тонкости создания визуального плагина
Post by: Artem on March 07, 2008, 14:51:34
в таких случаях, когда нельзя избавиться от фликов (мерцаний) другим способом, используют двойную буфферизацию, т.е. сначала рисуют все полностью на внутреннем буфере (на Bitmapе, как правило), а потом выводят готовое изображение на DC.

Вот небольшой пример:

procedure DisplayRender(DC: HDC; AData: PVisualData); stdcall;
var
  ABitmap: TBitmap;
begin
  ABitmap := TBitmap.Create; // создаем внутренний буфер
  try
    ABitmap.Width := W;
    ABitmap.height := H; // размеры дисплея приходят на Resize
    Paint(ABitmap.Canvas.Handle, AData); // наша внутренняя отрисовка
    BitBlt(DC, 0, 0, W, H, ABitmap.Canvas.Handle, 0, 0, SRCCOPY); // Выводим с буфера на дисплей
  finally
    ABitmap.Free;
  end;
end;

P.S. По-хорошему, в нашем случае, лучше будет так поступить:
+ буфер создавать и убивать при создании / дестрое плагина (чтобы при отрисовке каждый раз это не делать)
+ Ресайзить буфер при вызове функции Resize, которая передает координаты

Забыл:

>>ак же интересно, как сам плеер считывает данные с холста для отрисовки или отрисовка происходит в холст плеера напрямую?

2-ая буферизация используется только для полноэкранного режима
Title: Re: Тонкости создания визуального плагина
Post by: HardWareMan on March 11, 2008, 05:23:42
в таких случаях, когда нельзя избавиться от фликов (мерцаний) другим способом, используют двойную буфферизацию, т.е. сначала рисуют все полностью на внутреннем буфере (на Bitmapе, как правило), а потом выводят готовое изображение на DC.

Вот небольшой пример:

procedure DisplayRender(DC: HDC; AData: PVisualData); stdcall;
var
  ABitmap: TBitmap;
begin
  ABitmap := TBitmap.Create; // создаем внутренний буфер
  try
    ABitmap.Width := W;
    ABitmap.height := H; // размеры дисплея приходят на Resize
    Paint(ABitmap.Canvas.Handle, AData); // наша внутренняя отрисовка
    BitBlt(DC, 0, 0, W, H, ABitmap.Canvas.Handle, 0, 0, SRCCOPY); // Выводим с буфера на дисплей
  finally
    ABitmap.Free;
  end;
end;
О, это должно проканать, ато я пытался TCanvas намутить и  ничего не получалось...
P.S. По-хорошему, в нашем случае, лучше будет так поступить:
+ буфер создавать и убивать при создании / дестрое плагина (чтобы при отрисовке каждый раз это не делать)
+ Ресайзить буфер при вызове функции Resize, которая передает координаты
Угу, так и делаем.
Забыл:

>>ак же интересно, как сам плеер считывает данные с холста для отрисовки или отрисовка происходит в холст плеера напрямую?

2-ая буферизация используется только для полноэкранного режима
Вот почему в фулскрине не мигает... ;)
Title: Re: Тонкости создания визуального плагина
Post by: HardWareMan on March 11, 2008, 10:07:56
Вот поправил и избавился от мерцания! Теперь осталось проработать полноэкранный режим и все!
Забирать здесь (http://webfile.ru/1795228).
Title: Re: Тонкости создания визуального плагина
Post by: anon on March 17, 2008, 06:37:11
ребята помогите, я связался с разработчиком Winamp Wrapper (здесь писал об этом плагине https://www.aimp.ru/forum/index.php?topic=3730.0) и он говорит что ему нужен пример плагина визуализации  для создания аналогичного плагина для AIMP, запостите в этой теме, он прочитает
вот что он пишет:
Quote
The AIMP_Vis_Demo posted on https://www.aimp.ru/forum/index.php?topic=1733.0 by Spir1tus doesn't work here. Maybe it is for an old AIMP version.
I tried it by writing a main addon with the C++ example as base from the same topic (posted by Artem) but there is no way to get the wave form data needed for visualisation that way.
Then I tried to copy the visualisation plugin definitions from the Delphi SDK, but I was only able to crash AIMP after loading my test plugin.
Title: Re: Тонкости создания визуального плагина
Post by: Artem on March 17, 2008, 11:33:05
>>>Then I tried to copy the visualisation plugin definitions from the Delphi SDK, but I was only able to crash AIMP after loading my test plugin

Если возможно, пусть даст посмотреть плагин / часть, где он переносил код из дельфи, попробую выявить причину падения.
Title: Re: Тонкости создания визуального плагина
Post by: Barna on March 18, 2008, 07:35:06
Here's my test code in a short form:

Code: [Select]
#include "windows.h"

#define VIS_RQD_DATA_WAVE      1
#define VIS_RQD_DATA_SPECTRUM  2
#define VIS_RQD_NOT_SUSPEND    4

typedef char TWaveForm[2][512]; 
typedef BYTE TSpectrum[2][256];

typedef struct { BYTE LevelR, LevelL; TWaveForm Waveform; TSpectrum Spectrum; }TVisData, *PVisData;

typedef struct
{
  //BYTE Version;
  //DWORD DllInstance;
  PWCHAR (__stdcall *Author)();
  PWCHAR (__stdcall *PluginName)();
  PWCHAR (__stdcall *PluginInfo)();
  DWORD  (__stdcall *PluginFlags)();
  BOOL   (__stdcall *Initialize)();
  void   (__stdcall *Deinit)();
  void   (__stdcall *DisplayClicked)(int x, int y);
  void   (__stdcall *DisplayRender)(HDC Canvas, PVisData pVD );
  void   (__stdcall *DisplayResize)(int NewW, int NewH );
}TAIMP2VisualPlugin, *PAIMP2VisualPlugin;


BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) { return TRUE; }

PWCHAR __stdcall Author() { return L"Test Author"; }
PWCHAR __stdcall PluginName() { return L"Test Visual Plugin"; }
PWCHAR  __stdcall PluginInfo() { return L""; }
DWORD   __stdcall PluginFlags() { return VIS_RQD_DATA_WAVE|VIS_RQD_DATA_SPECTRUM|VIS_RQD_NOT_SUSPEND; }
void __stdcall Resize(int NewW, int NewH ) { }
void __stdcall Render(HDC Canvas, PVisData pVD ) { }
void __stdcall Deinit() { }
void __stdcall Clicked(int x, int y) { }
BOOL __stdcall Initialize();

TAIMP2VisualPlugin plugin =
{
  //1/*PLUGIN_VERSION*/,
  //0,
  Author,
  PluginName,
  PluginInfo,
  PluginFlags,
  Initialize,
  Deinit,
  Clicked,
  Render,
  Resize,
};

extern "C" __declspec( dllexport ) PAIMP2VisualPlugin AIMP_QueryVisual()
{
  MessageBox(NULL, L"AIMP_QueryVisual", L"", 0);
  return &plugin;
}

BOOL __stdcall Initialize()
{
  MessageBoxW(NULL, L"Initialize", L"",0);
  return TRUE;
}
Title: Re: Тонкости создания визуального плагина
Post by: Artem on March 18, 2008, 11:49:45
Hm, You conversion is invalid, IAIMP2VisualPlugin is not a struct, is interface.

Interfaces declarate as (for example):

class  IAIMPClassicPlayer
   : public IUnknown
{
public:
    virtual int      __stdcall   Version() = 0;
    virtual boolean __stdcall   PlayTrack(HPLS APlaylistID, int ATrackID) = 0;
   virtual void    __stdcall   PlayOrResume() = 0;
   virtual void    __stdcall   Pause() = 0;
   virtual void    __stdcall   Stop() = 0;
   virtual void    __stdcall   NextTrack() = 0;
   virtual void    __stdcall   PrevTrack() = 0;
};
Title: Re: Тонкости создания визуального плагина
Post by: Barna on March 19, 2008, 01:58:44
hmm, the best thing I could come up with is the following, which still crashes AIMP the same way:

Code: [Select]
#include "windows.h"

#define VIS_RQD_DATA_WAVE      1
#define VIS_RQD_DATA_SPECTRUM  2
#define VIS_RQD_NOT_SUSPEND    4

typedef char TWaveForm[2][512]; 
typedef BYTE TSpectrum[2][256];

typedef struct { BYTE LevelR, LevelL; TWaveForm Waveform; TSpectrum Spectrum; } TVisData, *PVisData;

class IAIMP2VisualPlugin : public IUnknown
{
public:
  virtual PWCHAR  __stdcall AuthorName() = 0;
  virtual PWCHAR  __stdcall PluginName() = 0;
  virtual PWCHAR  __stdcall PluginInfo() = 0;
  virtual DWORD   __stdcall PluginFlags() = 0;
  virtual boolean __stdcall Initialize() = 0;
  virtual void    __stdcall Deinitialize() = 0;
  virtual void    __stdcall DisplayClick(int x, int y) = 0;
  virtual void    __stdcall DisplayRender(HDC Canvas, PVisData pVD) = 0;
  virtual void    __stdcall DisplayResize(int NewW, int NewH) = 0;

  long __stdcall QueryInterface(const struct _GUID &,void ** )
  { MessageBoxW(NULL, L"IAIMP2VisualPlugin::QueryInterface", L"",0); return 1; }

  unsigned long __stdcall AddRef(void)
  { MessageBoxW(NULL, L"IAIMP2VisualPlugin::AddRef", L"",0); return 1; }

  unsigned long __stdcall Release(void)
  { MessageBoxW(NULL, L"IAIMP2VisualPlugin::Release", L"",0); return 1; }

  long __stdcall CreateInstance(struct IUnknown *,const struct _GUID &,void ** )
  { MessageBoxW(NULL, L"IAIMP2VisualPlugin::CreateInstance", L"",0); return 1; }

  long __stdcall LockServer(int)
  { MessageBoxW(NULL, L"IAIMP2VisualPlugin::LockServer", L"",0); return 1; }
};

class TAIMP2VisualPlugin : public IAIMP2VisualPlugin
{
public:
  PWCHAR  __stdcall AuthorName() { return L"Test Author"; }
  PWCHAR  __stdcall PluginName() { return L"Test Visual Plugin"; }
  PWCHAR  __stdcall PluginInfo() { return L""; }
  DWORD   __stdcall PluginFlags() { return VIS_RQD_DATA_WAVE|VIS_RQD_DATA_SPECTRUM|VIS_RQD_NOT_SUSPEND; }
  boolean __stdcall Initialize() { MessageBoxW(NULL, L"Initialize", L"",0); return TRUE; }
  void __stdcall Deinitialize() { }
  void __stdcall DisplayClick(int x, int y) { }
  void __stdcall DisplayRender(HDC Canvas, PVisData pVD ) { }
  void __stdcall DisplayResize(int NewW, int NewH ) { }
} VisualPlugin;

BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) { return TRUE; }

extern "C" __declspec( dllexport ) IAIMP2VisualPlugin* AIMP_QueryVisual()
{
  MessageBox(NULL, L"AIMP_QueryVisual", L"", 0);
  return &VisualPlugin;
}

As you can see, I don't have the slightest clue about COM programming... So I guess I need to wait until I can get a working C++ example of a visual plugin for AIMP. The only way so far for me with C++ seems to be Sonique plugin, unfortunately I need support for at least the DisplayClick function (which is available in Sonique Plugin API but not called/supported by AIMP). Plus actual usage of the AIMP2 API via IAIMP2Controller would be useful.
Maybe Spir1tus can post a working version of AIMP_Vis_Demo.rar from https://www.aimp.ru/forum/index.php?topic=1733.0 ?
Title: Re: Тонкости создания визуального плагина
Post by: Artem on March 19, 2008, 18:38:53
See at attach the demo project (originally by Spir1tus with my correction)
Title: Re: Тонкости создания визуального плагина
Post by: Barna on March 20, 2008, 04:39:24
Thanks, got something working now. Should be able to release a first version soon.

Short question, is there a way to get a IAIMP2Controller or something like that?
For now I use the Winamp emulation provided by AIMP's own "Winamp v1.x" window. A lot of stuff works already anyway, so it's not too urgent :-)
Title: Re: Тонкости создания визуального плагина
Post by: HardWareMan on March 20, 2008, 19:56:27
Отличная визуализация! +1. Напомнила старенький "Маяк" :)
Правда не во всех скинах нормально работает... :(
1. Это не Маяковый лума, а Радиотехнический.
2. Знаю, это вообще был тестовый проект. Шрифт средствами канваса нельзя написать, поэтому при других аспектах он косячит.
Я хочу попробовать отрендерить на еще одну поверхность шрифты и разметку в статический рисунок и потом переносить масштабированно (будет растягивать и т.д., но будет красиво). Так же, есть план занести туда изображения всех экранчиков Маяка (их всего 3) и добавить экранчик магнитофона Радиотехники (текущий - с усила, от мафона со счетчиком).
Title: Re: Тонкости создания визуального плагина
Post by: Barbiturat on March 26, 2008, 21:02:43
1. Это не Маяковый лума, а Радиотехнический.
Вообще подобные "экранчики" были на многих советских магниофонах: "Юпитер","Маяк","Орель","Яуза","Радиотехника","Электроника"и т.д. В большинстве своем они идентичные, так что определить с какого ты рисовал невозможно  :)
Title: Re: Тонкости создания визуального плагина
Post by: HardWareMan on March 29, 2008, 10:34:28
Вообще подобные "экранчики" были на многих советских магниофонах: "Юпитер","Маяк","Орель","Яуза","Радиотехника","Электроника"и т.д. В большинстве своем они идентичные, так что определить с какого ты рисовал невозможно  :)
Согласен, но маяковский длинный. Очень длинный. %) А конкретный этот я рисовал с усилка радиотехнического, коим и пользуюсь до сих пор (естественно прокачав некоторые параметры ;)).
Title: Re: Тонкости создания визуального плагина
Post by: MisterExciter on April 20, 2009, 11:16:59
Вопрос как раз о тонкости.

В окне плагинов, в списке "Подключенные плагины", есть кнопочка "Настройки".
Подскажите, что в коде Delphi замутить, чтобы можно было кликнуть эту кнопку и получить доступ к настройкам плагина. Поискал в SDK, но сходу не нашёл.
Нужен просто пример для зацепки, в остальном разберусь.
Title: Re: Тонкости создания визуального плагина
Post by: Artem on April 20, 2009, 13:10:10
Подскажите, что в коде Delphi замутить, чтобы можно было кликнуть эту кнопку и получить доступ к настройкам плагина.

Эта кнопка не действует для визуальных плагинов.
Title: Re: Тонкости создания визуального плагина
Post by: Chaos on May 04, 2009, 05:32:49
Зато для них отлично действует клик по дисплею.