Winamp'a Plugin Yazmak


Winamp'a Plugin Yazmak


Belki ileride işinize yarar diye yazdığım ufak bir winamp plugini paylaşmak istedim. Pluginin yaptığı şey F12 tuşuna basıldığında çalmakta olan şarkıyı plugin ayarlarında daha önceden belirttiğimiz yere kopyalamak. Bu ne için gerekli olur diye düşünebilirsiniz. Şöyle ki: Diyelim ki arkadaşınızdan binlerce müzikten oluşan ufak bir müzik arşivi aldınız. Belki çoğu müzik hoşunuza gitmeyecek. Hoşunuza gidenleri ayıklamak istediğinizde ise çok zorlanacaksınız. Hele çoğu şarkının winampta görünen hali(title) ile diskteki ismi farklıdır. Iç içe klasörler de işin içine girdi mi dosyaları arar durursunuz. Benim başıma bu durum çok geldiği için bir plugin yazayım dedim. Ufak bir araştırma sonucu edindiğim bilgileri paylaşmak istedim.

Plugin yazabilmek için öncelikle WinampSDK yı indirip yüklemek gerekiyor. Kurulum dosyasını aşağıdaki bağlantıdan indirebilirsiniz.

WinampSDK plugin yazabilmek için gerekli başlık dosyalarını içermektedir. WinampSDK yı kurduğunuzda default olarak "C:\Program Files\Winamp SDK" klasörü içine kurulmaktadır. Kullandığımız IDE ayarlarından yada proje ayarlarından bu klasörü ortama tanıtmış olmamız gerekmektedir.

Winamp çok sayıda plugin(eklenti) türü desteklemektedir. Winamp bu pluginleri yüklerken hangi türde olduğunu plugin dosyalarının ön eklerine bakarak anlar. Plugin türleri aşağıdaki gibi sıralanmaktadır.

  •  in_*.dll - Giriş pluginleri(input plugins). Değişik ses formatlarınının okunup winamp tarafından çalınmasını sağlayan pluginlerdir.
  • out_*.dll - Çıkış pluginleri(output plugins). Sesin bilgisayar donanımı tarafından çalınabilmesini sağlayan pluginlerdir.
  • gen_*.dll - Genel amaçlı pluginler (general purpose plugins). Winampın herhangi bir yerine müdahale etmek yada bilgiler almak için kullanılan pluginlerdir.
  • vis_*.dll - Çalan müziğe göre görsel efektler oluşturan pluginler (visualizer plugins).
  • dsp_*.dll - Ses efekt pluginleri (audio effects plugins). Ses içeriğine etki ederek değişik efektler oluşturmayı sağlayan pluginlerdir. Sesin Basslı, tizli, robotik çalması gibi.
  • ml_*.dll - Ses/Görüntü kütüphanesi pluginleri (media library plugins) (bu pluginler gen_ml.dll plugini tarafından okunur)
  • pmp_*.dll - Taşınabilir ortam oynatıcı pluginleri (portable media player plugins) (ml_pmp.dll tarafından okunurlar. Yani bir pluginin plugini tarafından okunurlar.)
  • nsvdec_*.dll - NVS çözücü pluginleri (NSV decoder plugins)
  • enc_*.dll - Ses dönüştürücü pluginleri (audio encoder plugins)
  • W5S - Winamp sistem pluginleri (Winamp 5 System) "c:program fileswinampsystem" klasörü içinde uzantıları .w5s olan pluginlerdir.
  • WAC - Winamp bileşen pluginleri (Winamp Component) "c:program fileswinamppluginsfreeformwacs" klasörü içinde bulunurlar .wac dosya uzantısına sahiptirler. gen_ff.dll plugini tarafından okunurlar.

Winamp her açılışında "C:\Program Files\Winamp\Plugins" klasörü içinde bulunan pluginleri otomatik olarak yükler. Yazdığımız pluginlerin okunabilmesi için onları bu klasöre koymamız gerekiyor. Pluginimiz okunduğunda Winamp tercihleri kısmında aşağıdaki gibi görünecektir.

Aşağıdaki winamp pluginimizin çalışma mantığı da kabaca şöyledir. Winamp dll imiz içinde export edilmiş olan "winampGetGeneralPurposePlugin" fonksiyonunu çağırıp "winampGeneralPurposePlugin" yapısından bir instanceyi alıp içinde belirtilen callback fonksiyonlarını gerekli zamanlarda işletir. Kaynak kodlar da gerekli gördüğüm yerlerde ufak açıklamalar yaptım. Winamp ile iletişime geçmeyi plugin yüklenirken winampın yapımıza verdiği pencere idsine windows mesajları göndererek yapıyoruz. Winampa ne tür mesajlar gönderilerek neler elde edeceğimiz yada neler yaptırabileceğimiz gibi bilgileri wa_ipc.h başlık dosyası içine bakarak, inceleyerek öğreniyoruz. wa_ipc.h dosyası genel amaçlı pluginler yazmak için gerekli fonksiyonları içeren başlık dosyasıdır. Diğer tür pluginlerin çalışma mantığı da buna benzedir.

WinampPlugin.h
C/C++ kodu:
#pragma once

#include <windows>

// plugin versiyonu (değiştirilmemesi gerekiyor)
#define GPPHDR_VER 0x10

// plugin ismi
#define PLUGIN_NAME "BTMusicCopy"


//Plugin ile ilgili bilgileri ihtiva eden yapı
typedef struct {
    int version;                   // Plugin yapısının versiyonu
    char *description;             // Pluginin ismi
    int (*init)();                 // Plugin yüklenirken çağırılacak fonksiyon
    void (*config)();              // Winamp ta plugine ait ayarları göster denildiğinde çağırılacak fonksiyon
    void (*quit)();                // Plugin serbest bırakılırken çağırılacak fonksiyon
    HWND hwndParent;               // Winamp penceresinin id sini tutar
    HINSTANCE hDllInstance;        // Pluginin/Dll in instancesini tutar.
}winampGeneralPurposePlugin; 

WinampPlugin.cpp  
C/C++ kodu:

#include "stdafx.h"
#include <windows.h>
#include "WinampPlugin.h"
#include "Config.h"
#include "NetInteropUtils.h"
//WinampSDK klasörü içinde bulunmakta
#include <Winamp\wa_ipc.h>
 
using namespace WinampPlugin;
using namespace System::Threading;
using namespace System::IO;
 
 
ref class KEY{
public:
    void KeyListener();
};
 
//Plugin yüklenirken çağırılacak fonksiyon
int  init(void);
//Winamp ta plugine ait ayarları göster denildiğinde çağırılacak fonksiyon
void config(void);
//Plugin serbest bırakılırken çağırılacak fonksiyon
void quit(void);
 
//Yapının başlangıç değerlerini atıyoruz.
winampGeneralPurposePlugin plugin = {GPPHDR_VER,PLUGIN_NAME,init,config,quit,0,0};
 
bool IsKeyDown(Keys key)
{
    short retVal = GetKeyState((int)key);
    if ((retVal & 0x8000) == 0x8000)
        return true;
    else return false;
}
 
 
int init() {
    /*
      Pluginimiz yüklendiğinde winamp açık olduğu sürece basılan 
      tuşları dinlemesi için bir thread oluşturuyoruz.
    */
    Thread ^th;
    KEY ^object=gcnew KEY();
    th=gcnew Thread(gcnew ThreadStart(object,&KEY::KeyListener));
    th->Name="KeyListener";
    th->Start();
    return 0;
}
 
void KEY::KeyListener()
{
    while(1){
        //Threadin sistemi yormaması için 20ms de bir basılan tuşları kontrol ediyoruz.
        Sleep(20);
        //Threadin winamp ile iletişimi sırasında başka windows mesajlarının da işlenmesini sağlıyoruz.
        Application::DoEvents();
        //F12 kısayol tuşuna basıldığında çalmakta olan dosyayı ayarlar ekranında belirtilen klasöre kopyala
        if (IsKeyDown(Keys::F12))
        {            
            String ^destPath=(String^)Application::UserAppDataRegistry->GetValue("DestinationPath");
            //Çalmakta olan şarkının indexini al
            int pos=SendMessage(plugin.hwndParent,WM_WA_IPC,0,IPC_GETLISTPOS);
            //Indexi verilen şarkının dosya yolunu al
            LRESULT lpres=SendMessage(plugin.hwndParent,WM_WA_IPC,pos,IPC_GETPLAYLISTFILE);
            //Dönen sonucu char pointere cast ediyoruz.
            char *name=reinterpret_cast<char *>(lpres);
            //Dosya bilgisini al
            FileInfo ^finfo= gcnew FileInfo(NetInterops::ConvertStr(name));
            try
            {
                //Dosyayı belirtilen konuma kopyala
                File::Copy(NetInterops::ConvertStr(name),destPath+"\\"+finfo->Name,false);
                //Kopyalama işlemi başarılı olursa bip sesi çaldır.
                Beep(1000,500);
            }
            catch (Exception^ex)
            {
                MessageBox::Show("Dosya kopyalanamadı yada zaten hedef klasörde mevcut.","",MessageBoxButtons::OK,MessageBoxIcon::Error);
            }            
        }        
    }
}
 
void config() 
{
    Config ^config =gcnew Config();
    config->Show();    
}
 
void quit() {
}
 
//Winampın plugini yüklerkenki giriş noktası.
extern "C" __declspec(dllexport) winampGeneralPurposePlugin * winampGetGeneralPurposePlugin() {
    return &plugin;
}

Config.h panel sınıfının sadece ilgili kısımları.  
C/C++ kodu:
 
..
..
    private: System::Void Config_Load(System::Object^  sender, System::EventArgs^  e) 
     {
         try
         {
             //Uygulamamıza ait registry ayarlarından DestinationPath değerini oku.
             textBoxFilePath->Text = (String^)Application::UserAppDataRegistry->GetValue("DestinationPath");
         }
         catch(Exception ^ex){}
     }
    private: System::Void buttonSelectFolder_Click(System::Object^  sender, System::EventArgs^  e) 
     {
         //Klasör seçim diyalog kutusunu göster
         FolderBrowserDialog ^folders=gcnew FolderBrowserDialog();
         folders->RootFolder= Environment::SpecialFolder::Desktop;
         folders->Description= "Klasör Seçimi";
         folders->SelectedPath=(String^)Application::UserAppDataRegistry->GetValue("DestinationPath");
         if (::DialogResult::OK==folders->ShowDialog())
         {
             //Diyalog kutusundan seçilen klasörü ilgili kutucuğa ata
             textBoxFilePath->Text=folders->SelectedPath;
         }
     }
    private: System::Void buttonSavePath_Click(System::Object^  sender, System::EventArgs^  e) 
    {
     try
     {
         //Seçilen klasörü registry ye kaydet
         Application::UserAppDataRegistry->SetValue("DestinationPath", textBoxFilePath->Text);
         MessageBox::Show("Ayarlar kaydedilmiştir.");
         this->Close();
     }
     catch(Exception ^ex){}
     
    }
..
..

Dersimizin kaynak kodları ve derlenmiş plugin dosyaları. Uygulamamızın çalışabilmesi için Visual C++ 2008 çalışma kütüphanelerinin ve .Net Framework 2.0 ın sistemimizde yüklü olması gerekmektedir. En az WinXP Sp2 kullanıyorsanız bunlar zaten yüklü olduğu için ayrıca bişi yüklemenize gerek kalmayacaktır.

Kaynak Kod:

Yararlanılan kaynak http://dev.winamp.com/wiki/Plug-in_Developer

Bir sonraki dersimizde görüşünceye kadar kendinize iyi bakın.

Bilgin Terzi ( 3ddreams ) 

Yorumlar

Bu blogdaki popüler yayınlar

Doxygen Kullanımı

SDL Nedir?