479 lines
10 KiB
C
479 lines
10 KiB
C
|
// Winamp test dsp library 0.9 for Winamp 2
|
||
|
// Copyright (C) 1997, Justin Frankel/Nullsoft
|
||
|
// Feel free to base any plugins on this "framework"...
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <commctrl.h>
|
||
|
#include <math.h>
|
||
|
#include "../Winamp/dsp.h"
|
||
|
#include "resource.h"
|
||
|
|
||
|
// avoid stupid CRT silliness
|
||
|
//BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
|
||
|
//{
|
||
|
// return TRUE;
|
||
|
//}
|
||
|
|
||
|
|
||
|
// pitch value
|
||
|
int g_pitch=100;
|
||
|
|
||
|
// pitch control window
|
||
|
HWND pitch_control_hwnd;
|
||
|
|
||
|
// auxilary pitch buffer (for resampling from)
|
||
|
short *pitch_buffer=NULL;
|
||
|
int pitch_buffer_len=0;
|
||
|
int quit_pitch=0;
|
||
|
|
||
|
// module getter.
|
||
|
winampDSPModule *getModule(int which);
|
||
|
|
||
|
void config(struct winampDSPModule *this_mod);
|
||
|
int init(struct winampDSPModule *this_mod);
|
||
|
int initpitch(struct winampDSPModule *this_mod);
|
||
|
void quit(struct winampDSPModule *this_mod);
|
||
|
void quitpitch(struct winampDSPModule *this_mod);
|
||
|
int modify_samples1(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate);
|
||
|
int modify_samples2(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate);
|
||
|
int modify_samples3(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate);
|
||
|
int modify_samples_lopass(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate);
|
||
|
int modify_samples_hipass(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate);
|
||
|
|
||
|
static INT_PTR CALLBACK pitchProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
|
||
|
|
||
|
// Module header, includes version, description, and address of the module retriever function
|
||
|
typedef struct {
|
||
|
int version; // DSP_HDRVER
|
||
|
char *description; // description of library
|
||
|
winampDSPModule* (*getModule)(int); // module retrieval function
|
||
|
int (*sf)(int);
|
||
|
} winampDSPHeaderEx;
|
||
|
|
||
|
int sf(int v)
|
||
|
{
|
||
|
int res;
|
||
|
res = v * (unsigned long)1103515245;
|
||
|
res += (unsigned long)13293;
|
||
|
res &= (unsigned long)0x7FFFFFFF;
|
||
|
res ^= v;
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
winampDSPHeaderEx hdr = { DSP_HDRVER+1, "Nullsoft DSP v0.35 for Winamp 2ARG", getModule, sf };
|
||
|
|
||
|
|
||
|
// first module
|
||
|
winampDSPModule mod =
|
||
|
{
|
||
|
"Nullsoft Echo v0.2",
|
||
|
NULL, // hwndParent
|
||
|
NULL, // hDllInstance
|
||
|
config,
|
||
|
init,
|
||
|
modify_samples1,
|
||
|
quit
|
||
|
};
|
||
|
|
||
|
|
||
|
// second module
|
||
|
winampDSPModule mod2 =
|
||
|
{
|
||
|
"Nullsoft Stereo Voice Removal v0.2",
|
||
|
NULL, // hwndParent
|
||
|
NULL, // hDllInstance
|
||
|
config,
|
||
|
init,
|
||
|
modify_samples2,
|
||
|
quit
|
||
|
};
|
||
|
|
||
|
winampDSPModule mod3 =
|
||
|
{
|
||
|
"Nullsoft Pitch/Tempo Control v0.2",
|
||
|
NULL, // hwndParent
|
||
|
NULL, // hDllInstance
|
||
|
config,
|
||
|
initpitch,
|
||
|
modify_samples3,
|
||
|
quitpitch
|
||
|
};
|
||
|
|
||
|
winampDSPModule mod4 =
|
||
|
{
|
||
|
"Nullsoft Lowpass Filter v1.0",
|
||
|
NULL, // hwndParent
|
||
|
NULL, // hDllInstance
|
||
|
config,
|
||
|
init,
|
||
|
modify_samples_lopass,
|
||
|
quit
|
||
|
};
|
||
|
winampDSPModule mod5 =
|
||
|
{
|
||
|
"Nullsoft Highpass Filter v1.0",
|
||
|
NULL, // hwndParent
|
||
|
NULL, // hDllInstance
|
||
|
config,
|
||
|
init,
|
||
|
modify_samples_hipass,
|
||
|
quit
|
||
|
};
|
||
|
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
extern "C" {
|
||
|
#endif
|
||
|
// this is the only exported symbol. returns our main header.
|
||
|
__declspec( dllexport ) winampDSPHeaderEx *winampDSPGetHeader2()
|
||
|
{
|
||
|
return &hdr;
|
||
|
}
|
||
|
#ifdef __cplusplus
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// getmodule routine from the main header. Returns NULL if an invalid module was requested,
|
||
|
// otherwise returns either mod1 or mod2 depending on 'which'.
|
||
|
winampDSPModule *getModule(int which)
|
||
|
{
|
||
|
switch (which)
|
||
|
{
|
||
|
case 0: return &mod;
|
||
|
case 1: return &mod2;
|
||
|
case 2: return &mod3;
|
||
|
// case 3: return &mod4;
|
||
|
// case 4: return &mod5;
|
||
|
default:return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// configuration. Passed this_mod, as a "this" parameter. Allows you to make one configuration
|
||
|
// function that shares code for all your modules (you don't HAVE to use it though, you can make
|
||
|
// config1(), config2(), etc...)
|
||
|
void config(struct winampDSPModule *this_mod)
|
||
|
{
|
||
|
MessageBox(this_mod->hwndParent,"This module is Copyright(C) 1997-1999, Nullsoft\n"
|
||
|
"Notes:\n"
|
||
|
" * 8 bit samples aren't supported.\n"
|
||
|
" * Pitch control rules!\n"
|
||
|
" * Voice removal sucks (works about 10% of the time)!\n"
|
||
|
" * Echo isn't very good!\n"
|
||
|
"etc... this is really just a test of the new\n"
|
||
|
"DSP plug-in system. Nothing more.",
|
||
|
"Configuration",MB_OK);
|
||
|
}
|
||
|
|
||
|
int init(struct winampDSPModule *this_mod)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
int initpitch(struct winampDSPModule *this_mod)
|
||
|
{
|
||
|
pitch_buffer_len=0;
|
||
|
pitch_buffer=NULL;
|
||
|
quit_pitch=0;
|
||
|
ShowWindow((pitch_control_hwnd=CreateDialog(this_mod->hDllInstance,MAKEINTRESOURCE(IDD_DIALOG1),this_mod->hwndParent,pitchProc)),SW_SHOW);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// cleanup (opposite of init()). Destroys the window, unregisters the window class
|
||
|
void quit(struct winampDSPModule *this_mod)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void quitpitch(struct winampDSPModule *this_mod)
|
||
|
{
|
||
|
if (this_mod == &mod3)
|
||
|
{
|
||
|
if (pitch_buffer) GlobalFree(pitch_buffer);
|
||
|
pitch_buffer_len=0;
|
||
|
pitch_buffer=NULL;
|
||
|
quit_pitch=1;
|
||
|
if (pitch_control_hwnd)
|
||
|
{
|
||
|
DestroyWindow(pitch_control_hwnd);
|
||
|
pitch_control_hwnd=0;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
short echo_buf[65536], echo_buf2[65536];
|
||
|
|
||
|
int modify_samples1(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate)
|
||
|
{
|
||
|
// echo doesn't support 8 bit right now cause I'm lazy.
|
||
|
if (bps==16)
|
||
|
{
|
||
|
int x,s;
|
||
|
s = numsamples*nch;
|
||
|
|
||
|
memcpy(echo_buf2, echo_buf, s*2);
|
||
|
memcpy(echo_buf, echo_buf+s, s*2);
|
||
|
memcpy(echo_buf+s, echo_buf+s*2, s*2);
|
||
|
memcpy(echo_buf+s*2,echo_buf+s*3, s*2);
|
||
|
memcpy(echo_buf+s*3,samples, s*2);
|
||
|
|
||
|
for (x = 0; x < s; x ++)
|
||
|
{
|
||
|
int s = samples[x]/2+echo_buf2[x]/2;
|
||
|
samples[x] = (s>32767?32767:s<-32768?-32768:s);
|
||
|
}
|
||
|
}
|
||
|
return numsamples;
|
||
|
}
|
||
|
|
||
|
int modify_samples3(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate)
|
||
|
{
|
||
|
int pitch=g_pitch;
|
||
|
int rlen =numsamples*bps/8*nch;
|
||
|
int index=0, x;
|
||
|
int n;
|
||
|
int dindex;
|
||
|
if (quit_pitch || g_pitch==100) return numsamples;
|
||
|
if (g_pitch > 200) g_pitch=200;
|
||
|
if (g_pitch < 50) g_pitch=50;
|
||
|
pitch = 100000/pitch;
|
||
|
n=(numsamples*pitch)/1000;
|
||
|
dindex=(numsamples<<11)/n;
|
||
|
if (pitch_buffer_len < rlen)
|
||
|
{
|
||
|
pitch_buffer_len = rlen;
|
||
|
GlobalFree(pitch_buffer);
|
||
|
pitch_buffer=GlobalAlloc(GMEM_FIXED,rlen);
|
||
|
}
|
||
|
if (bps == 16 && nch == 2)
|
||
|
{
|
||
|
short *buf=pitch_buffer;
|
||
|
memcpy(buf,samples,rlen);
|
||
|
for (x = 0; x < n; x ++)
|
||
|
{
|
||
|
int p=(index>>11)<<1;
|
||
|
index+=dindex;
|
||
|
samples[0] = buf[p];
|
||
|
samples[1] = buf[p+1];
|
||
|
samples+=2;
|
||
|
}
|
||
|
return n;
|
||
|
}
|
||
|
else if (bps == 16 && nch == 1)
|
||
|
{
|
||
|
short *buf=pitch_buffer;
|
||
|
memcpy(buf,samples,rlen);
|
||
|
for (x = 0; x < n; x ++)
|
||
|
{
|
||
|
int p=(index>>11);
|
||
|
index+=dindex;
|
||
|
*samples++ = buf[p];
|
||
|
}
|
||
|
return n;
|
||
|
}
|
||
|
return numsamples;
|
||
|
}
|
||
|
|
||
|
|
||
|
int modify_samples2(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate)
|
||
|
{
|
||
|
int x = numsamples;
|
||
|
if (bps == 16)
|
||
|
{
|
||
|
short *a = samples;
|
||
|
if (nch == 2) while (x--)
|
||
|
{
|
||
|
int l, r;
|
||
|
l = a[1]-a[0];
|
||
|
r = a[0]-a[1];
|
||
|
if (l < -32768) l = -32768;
|
||
|
if (l > 32767) l = 32767;
|
||
|
if (r < -32768) r = -32768;
|
||
|
if (r > 32767) r = 32767;
|
||
|
a[0] = l;
|
||
|
a[1] = r;
|
||
|
a+=2;
|
||
|
}
|
||
|
}
|
||
|
return numsamples;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
int modify_samples_lopass(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate)
|
||
|
{
|
||
|
if (bps==16)
|
||
|
{
|
||
|
static int lastspl=0,lastspl2=0;
|
||
|
int x;
|
||
|
x=numsamples;
|
||
|
if (nch==1) while (x--)
|
||
|
{
|
||
|
int thisspl=*samples;
|
||
|
*samples++=(lastspl+thisspl)/2;
|
||
|
lastspl=thisspl;
|
||
|
}
|
||
|
else if (nch == 2) while (x--)
|
||
|
{
|
||
|
int thisspl=*samples;
|
||
|
*samples++=(lastspl+thisspl)/2;
|
||
|
lastspl=thisspl;
|
||
|
thisspl=*samples;
|
||
|
*samples++=(lastspl2+thisspl)/2;
|
||
|
lastspl2=thisspl;
|
||
|
}
|
||
|
}
|
||
|
return numsamples;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
|
||
|
enum FILTER_TYPE {
|
||
|
lowpass,highpass,bandpass
|
||
|
};
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
float m_a0,m_a1;
|
||
|
float m_b0,m_b1,m_b2;
|
||
|
float m_d1,m_d2;
|
||
|
float m_k;
|
||
|
} filter;
|
||
|
|
||
|
float Filter(filter *f, const float x )
|
||
|
{
|
||
|
float d0,y;
|
||
|
|
||
|
d0 = f->m_k*x - f->m_a1*f->m_d1 - f->m_a0*f->m_d2;
|
||
|
y = d0*f->m_b2 + f->m_d1*f->m_b1 + f->m_d2*f->m_b0;
|
||
|
f->m_d2 = f->m_d1;
|
||
|
f->m_d1 = d0;
|
||
|
|
||
|
return y;
|
||
|
}
|
||
|
|
||
|
|
||
|
void makefilter( filter *f, int t , float sample_rate , float cutoff , float dampening )
|
||
|
{
|
||
|
float a2,c;
|
||
|
|
||
|
c = (float)( 1.f / tan( 3.14159265359*cutoff / sample_rate ) );
|
||
|
a2 = 1.f + c*(c+dampening);
|
||
|
|
||
|
f->m_a1 = 2.f * (1.f - c*c) / a2;
|
||
|
f->m_a0 = (1.f + c*(c-dampening)) / a2;
|
||
|
f->m_d1 = f->m_d2 = 0.f;
|
||
|
|
||
|
switch( t )
|
||
|
{
|
||
|
case lowpass:
|
||
|
f->m_k = 1.f / a2;
|
||
|
f->m_b1 = 2.f;
|
||
|
f->m_b0 = 1.f;
|
||
|
break;
|
||
|
|
||
|
case highpass:
|
||
|
f->m_k = c*c / a2;
|
||
|
f->m_b1 = -2.f;
|
||
|
f->m_b0 = 1.f;
|
||
|
break;
|
||
|
|
||
|
case bandpass:
|
||
|
f->m_k = c*dampening / a2;
|
||
|
f->m_b1 = 0.f;
|
||
|
f->m_b0 = -1.f;
|
||
|
break;
|
||
|
}
|
||
|
f->m_b2 = 1.f;
|
||
|
}
|
||
|
|
||
|
int modify_samples_lopass(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate)
|
||
|
{
|
||
|
static int i;
|
||
|
static filter f1,f2;
|
||
|
if (!i)
|
||
|
{
|
||
|
i=1;
|
||
|
makefilter(&f1,bandpass,44100,1000.0,0.5);
|
||
|
makefilter(&f2,lowpass,44100,1.0,1.0);
|
||
|
}
|
||
|
if (bps==16)
|
||
|
{
|
||
|
int x;
|
||
|
x=numsamples;
|
||
|
if (nch == 2) while (x--)
|
||
|
{
|
||
|
int t=(int)Filter(&f1,*samples);
|
||
|
*samples++=min(max(t,-32768),32767);
|
||
|
t=(int)Filter(&f2,*samples);
|
||
|
*samples++=min(max(t,-32768),32767);
|
||
|
}
|
||
|
}
|
||
|
return numsamples;
|
||
|
}
|
||
|
|
||
|
#define mulspl(a,b) _mulspl((int)(a),(int)((b)*65536.0))
|
||
|
|
||
|
int _mulspl(int a, int b)
|
||
|
{
|
||
|
a *= b;
|
||
|
a >>= 16;
|
||
|
return a;
|
||
|
}
|
||
|
|
||
|
|
||
|
int modify_samples_hipass(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate)
|
||
|
{
|
||
|
if (bps==16 && nch==2)
|
||
|
{
|
||
|
static short splbuf[32768+2];
|
||
|
short int *spls=splbuf+nch;
|
||
|
int x;
|
||
|
memcpy(spls,samples,numsamples*sizeof(short)*nch);
|
||
|
x=numsamples;
|
||
|
while (x--)
|
||
|
{
|
||
|
int ch;
|
||
|
for (ch = 0; ch < nch; ch ++)
|
||
|
{
|
||
|
int r=mulspl(spls[0],0.93) + mulspl(spls[-nch],-0.93) + mulspl(samples[-nch],0.86);
|
||
|
samples[0] = max(min(r,32767),-32768);
|
||
|
spls++;
|
||
|
samples++;
|
||
|
}
|
||
|
}
|
||
|
memcpy(splbuf,&splbuf[numsamples*nch],nch*sizeof(short));
|
||
|
}
|
||
|
return numsamples;
|
||
|
}
|
||
|
|
||
|
|
||
|
static BOOL CALLBACK pitchProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
|
||
|
{
|
||
|
if (uMsg == WM_INITDIALOG)
|
||
|
{
|
||
|
SendDlgItemMessage(hwndDlg,IDC_SLIDER1,TBM_SETRANGEMAX,0,50);
|
||
|
SendDlgItemMessage(hwndDlg,IDC_SLIDER1,TBM_SETRANGEMIN,0,-50);
|
||
|
SendDlgItemMessage(hwndDlg,IDC_SLIDER1,TBM_SETPOS,1,1);
|
||
|
SendDlgItemMessage(hwndDlg,IDC_SLIDER1,TBM_SETPOS,1,0);
|
||
|
{
|
||
|
char str[123];
|
||
|
wsprintf(str,"%s%d%%",g_pitch>=100?"+":"",g_pitch-100);
|
||
|
SetDlgItemText(hwndDlg,IDC_BOOGA,str);
|
||
|
}
|
||
|
}
|
||
|
if (uMsg == WM_VSCROLL)
|
||
|
{
|
||
|
HWND swnd = (HWND) lParam;
|
||
|
if (swnd == GetDlgItem(hwndDlg,IDC_SLIDER1))
|
||
|
{
|
||
|
g_pitch = -SendDlgItemMessage(hwndDlg,IDC_SLIDER1,TBM_GETPOS,0,0)+100;
|
||
|
{
|
||
|
char str[123];
|
||
|
wsprintf(str,"%s%d%%",g_pitch>=100?"+":"",g_pitch-100);
|
||
|
SetDlgItemText(hwndDlg,IDC_BOOGA,str);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|