• Партнер

  • Привет, кул хацкер! Твою бы энергию - да в
    мирных целях 🙂 Вот мы и займёмся
    обустройством твоего любимого (надеюсь) mp3
    проигрывателя Winamp. Plugin для Winamp - обычная DLL
    со строго определённым интерфейсом. Вообще,
    любая прога, которая поддерживает plugin’ы,
    имеет свой стандартный интерфейс для
    обращения к ним. В данной статье мы
    рассмотрим интерфейс DSP (для создания
    звуковых эффектов, как то: ускорение/замедление
    звука, “звук вокруг” [он же surround] и т.п.).
    Эффект surround очень прост в реализации,
    потому я и выбрал его в качестве примера. В
    стерео сигнале два канала - левый и правый
    подаются на динамики в противофазе, что и
    обеспечивает эффект объёма. 

    Теперь о программной части реализации. В
    файле “dsp.h” объявлена внутренняя
    структура заголовка модуля (winampDSPModule) и
    заголовка plugin’a (winampDSPHeader). Также одна
    функция (winampDSPGetHeader2) объявлена “на экспорт”
    (см. файл “dsp.def”) - именно её Winamp выполняет
    при загрузке plugin’a. Она передаёт ему
    заголовок, который содержит в себе ссылку
    на функцию выбора модуля. Это и есть
    интерфейс связи Winamp’a с plugin’ом. А вот и сам
    исходник (Visual C++ 6.0):

    <dsp.h>:

    #define DSP_HDRVER 0x20 // Версия заголовка: 0x20 == 0.20 ==
    winamp 2.0

    typedef struct winampDSPModule
    {
    char *description; // Описание
    HWND hwndParent; // Окно вызывающей проги (в нашем
    случае WinAmp)
    HINSTANCE hDllInstance; // Handle нашей DLL (заполняется WinAmp'ом)

    // Функция окна для конфигурации плагина
    void (*Config)(struct winampDSPModule *this_mod);
    // Инициализация (возвращает 0 если успешно)
    int (*Init)(struct winampDSPModule *this_mod);
    // Модификация сэмплов (возвращает кол-во
    обработанных сэмплов)
    int (*ModifySamples)(struct winampDSPModule *this_mod,
    short int *samples, int numsamples,
    int bps, int nch, int srate);
    // Функция, вызываемая при "выгрузке"
    плагина
    void (*Quit)(struct winampDSPModule *this_mod);

    void *userData; // Данные ползователя (обычно не
    используется)
    } winampDSPModule;

    typedef struct
    {
    int version; // Для какой версии WinAmp'a ( DSP_HDRVER )
    char *description; // Описание (что плагин делает или
    кем написан)
    // Функция,возвращающая модуль (в одном
    плагине их может быть несколько)
    winampDSPModule* (*getModule)(int);
    } winampDSPHeader;

    typedef winampDSPHeader* (*winampDSPGetHeaderType)();

    <dsp.c>:

    #include <windows.h>
    #include "dsp.h"

    // "Главная" функция DLL - должна
    присутствовать в каждой DLL
    BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call,
    LPVOID lpReserved)
    {
    return TRUE;
    }

    // Функция, возвращающая один из модулей
    плагина
    winampDSPModule *getModule(int which);

    void config(struct winampDSPModule *this_mod);
    int init(struct winampDSPModule *this_mod);
    void quit(struct winampDSPModule *this_mod);
    int modify_samples(struct winampDSPModule *this_mod, short int *samples,
    int numsamples, int bps, int nch, int srate);

    // Заголовок модуля, который содержит:
    версию, описание,
    // адрес функции для "выдачи" модуля
    WinAmp'у
    winampDSPHeader hdr = { DSP_HDRVER,
    "Cool XAKEP surround plugin :)",
    getModule };

    winampDSPModule mod =
    {
    "Surround sound",
    NULL, // hwndParent (заполняется WinAmp'ом)
    NULL, // hDllInstance (заполняется WinAmp'ом)
    config,
    init,
    modify_samples,
    quit,
    NULL
    };

    // Это единственная экспортируемая функция (см.
    "dsp.def")
    // Возвращает заголовок со всей инфой о
    плагине
    winampDSPHeader *winampDSPGetHeader2()
    {
    return &hdr;
    }

    // Функция выдачи модуля WinAmp'у (Возвращает NULL,
    если запрос неправильный)
    winampDSPModule *getModule(int which)
    {
    if (which == 0)
    return &mod;
    else
    return NULL;
    }

    // Функция конфигурации (общая для всех
    модулей в плагине)
    void config(struct winampDSPModule *this_mod)
    {
    MessageBox(NULL,
    "This module is Copyright (C) 1999 by Starlight",
    "Configuration", MB_OK);
    }

    // Инициализация (в данном случае не нужна)
    int init(struct winampDSPModule *this_mod)
    {
    return 0;
    }

    // Функция, вызываемая при "выгрузке"
    // Если плагин создавал окна - удалять здесь
    void quit(struct winampDSPModule *this_mod)
    {
    }

    // А вот здесь и делается surround 🙂
    int modify_samples(struct winampDSPModule *this_mod, short int *samples,
    int numsamples, int bps, int nch, int srate)
    {
    int x;
    if (bps == 16 && nch == 2 /* если стерео */)
    for (x = 0; x < numsamples*nch; x += 2) {
    // на один из каналов сигнал идёт "перевёрнутым"
    int s = -samples[x]; 
    samples[x] = (s>32767 ? 32767 : s<-32768 ? -32768 : s);
    }
    return numsamples;
    }

    <dsp.def> :

    LIBRARY
    EXPORTS
    winampDSPGetHeader2=winampDSPGetHeader2

    <make.bat> :
    @cl /LD /MD /GD6f /Ox /Os /ID:\DS\VC98\Include dsp.c D:\DS\VC98\Lib\UUID.LIB D:\DS\VC98\Lib\MSVCRT.LIB
    D:\DS\VC98\Lib\USER32.LIB D:\DS\VC98\Lib\KERNEL32.LIB /link /def:dsp.def
    /opt:nowin98
    @del dsp.obj >nul
    @del dsp.exp >nul
    @del dsp.lib >nul
    (Только пропиши свои пути к VC++ 🙂

    Вот и всё - юзай на здоровье 🙂

    P.S. Special thanks for Anshkin Oleg aka Starlight.

    P.P.S. Если понадобится узнать, какую музыку
    гоняет твой друг/знакомый можно написать
    соответствующий plugin, который обо всём
    настучи... ну, в общем, оповестит тебя о
    появлении у него новых рульных mp3 🙂

    Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии