1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
var
SpecBuf : Pointer;
procedure UpdateSpectrum(uTimerID, uMsg, dwUser, dw1, dw2 : LongWord); stdcall;
type
TSingleArray = array of Single;
var
DC : HDC;
X, Y, Z,
I, J, sc : Integer;
Sum : Single;
fft : array[0..1023] of Single; // get the FFT data
ci : BASS_CHANNELINFO;
Buf : TSingleArray;
begin
if SpecMode = 3 then // waveform
begin
FillChar(SpecBuf^, SPECWIDTH * SPECHEIGHT, 0);
BASS_ChannelGetInfo(chan, ci); // get number of channels
SetLength(Buf, ci.chans * SPECWIDTH);
Y := 0;
BASS_ChannelGetData(chan, @buf, (ci.chans * SPECWIDTH * SizeOf(Single)) or BASS_DATA_FLOAT); // get the sample data (floating-point to avoid 8 & 16 bit processing)
for I := 0 to ci.chans - 1 do
begin
for X := 0 to SPECWIDTH - 1 do
begin
Z := Trunc((1 - Buf[X * Integer(ci.chans) + I]) * SPECHEIGHT / 2); // invert and scale to fit display
if Z < 0 then
Z := 0
else if Z >= SPECHEIGHT then
Z := SPECHEIGHT - 1;
if X = 0 then
Y := Z;
repeat // draw line from previous sample...
if Y < Z then
inc(Y)
else if Y > Z then
dec(Y);
if (I and 1) = 1 then
Byte(Pointer(Longint(SpecBuf) + Y * SPECWIDTH + X)^) := 127
else
Byte(Pointer(Longint(SpecBuf) + Y * SPECWIDTH + X)^) := 1;
until Y = Z;
end;
end;
end
else
begin
BASS_ChannelGetData(chan, @fft, BASS_DATA_FFT2048);
case SpecMode of
0 : // "normal" FFT
begin
FillChar(SpecBuf^, SPECWIDTH * SPECHEIGHT, 0);
Z := 0;
for X := 0 to pred(SPECWIDTH) div 2 do
begin
Y := Trunc(sqrt(fft[X + 1]) * 3 * SPECHEIGHT - 4); // scale it (sqrt to make low values more visible)
// Y := Trunc(fft[X + 1] * 10 * SPECHEIGHT); // scale it (linearly)
if Y > SPECHEIGHT then
Y := SPECHEIGHT; // cap it
if (X > 0) and (Z = (Y + Z) div 2) then // interpolate from previous to make the display smoother
while (Z >= 0) do
begin
Byte(Pointer(Longint(SpecBuf) + Z * SPECWIDTH + X * 2 - 1)^) := Z + 1;
dec(Z);
end;
Z := Y;
while (Y >= 0) do
begin
Byte(Pointer(Longint(SpecBuf) + Y * SPECWIDTH + X * 2)^) := Y + 1; // draw level
dec(Y);
end;
end;
end;
1 : // logarithmic, acumulate & average bins
begin
I := 0;
FillChar(SpecBuf^, SPECWIDTH * SPECHEIGHT, 0);
for X := 0 to BANDS - 1 do
begin
Sum := 0;
J := Trunc(Power(2, X * 10.0 / (BANDS - 1)));
if J > 1023 then
J := 1023;
if J <= I then
J := I + 1; // make sure it uses at least 1 FFT bin
sc := 10 + J - I;
while I < J do
begin
Sum := Sum + fft[1 + I];
inc(I);
end;
Y := Trunc((sqrt(Sum / log10(sc)) * 1.7 * SPECHEIGHT) - 4); // scale it
if Y > SPECHEIGHT then
Y := SPECHEIGHT; // cap it
while (Y >= 0) do
begin
FillChar(Pointer(Longint(SpecBuf) + Y * SPECWIDTH + X * (SPECWIDTH div BANDS))^, SPECWIDTH div BANDS - 2, Y + 1); // draw bar
dec(Y);
end;
end;
end;
2 : // "3D"
begin
for X := 0 to SPECHEIGHT - 1 do
begin
Y := Trunc(sqrt(fft[x + 1]) * 3 * 127); // scale it (sqrt to make low values more visible)
if Y > 127 then
Y := 127; // cap it
Byte(Pointer(Longint(SpecBuf) + X * SPECWIDTH + SpecPos)^) := 128 + Y; // plot it
end;
// move marker onto next position
SpecPos := (SpecPos + 1) mod SPECWIDTH;
for X := 0 to SPECHEIGHT do
Byte(Pointer(Longint(SpecBuf) + X * SPECWIDTH + SpecPos)^) := 255;
end;
end;
end;
// update the display
DC := GetDC(Window);
try
BitBlt(DC, 0, 0, SPECWIDTH, SPECHEIGHT, SpecDC, 0, 0, SRCCOPY);
finally
ReleaseDC(Window, DC);
end;
end; |
Partager