Привет, кул хацкер! Твою бы энергию — да в
мирных целях 🙂 Вот мы и займёмся
обустройством твоего любимого (надеюсь) 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 🙂

Оставить мнение

Check Also

LUKS container vs Border Patrol Agent. Как уберечь свои данные, пересекая границу

Не секрет, что если ты собрался посетить такие страны как США или Великобританию то, прежд…