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

Tips’n’Tricks из арсенала андроидовода. Самые интересные, полезные и нестандартные трюки с Android

Многие годы мы рассказывали про самые разные способы оптимизировать, модифицировать и твик…