remstart
Globals required:
dim signal() as SINUSOIDAL_WAVE
dim fftreal(1) as float
dim fftimag(1) as float
dim histogram(1) as integer
dim fftstage() as integer
dim spectrum_analysis() as FREQUENCY_DATA
dim waves() as WAVEOBJECT
remend
#constant MAX_VOLUME = 32767.0
#constant WAVE_FORMAT_PCM = 1
#constant SIZEOF_winWAVEFORMATEX = 18
#constant SIZEOF_dbWAVEFORMATEX = 28
remstart
DBPro aligns the WAVEFORMATEX structure on DWORD boundaries, so the image in
memory is not directly interchangeable with a RAW wavefile. In addition, RAW
wavefiles use a format called RIFF, as does MIDI. See the functions for RAW
wavefile loading and saving for implementation details.
remend
#constant _WFORMAT = 0
#constant _NCHANNELS = 4
#constant _NSAMPLESPERSEC = 8
#constant _NAVGBYTESPERSEC = 12
#constant _NBLOCKALIGN = 16
#constant _WBITSPERSAMPLE = 20
#constant _CBSIZE = 24
rem Wave types. Use these to tell the code how to generate a wave.
#constant SINEWAVE = 0
#constant SQUAREWAVE = 1
#constant SAWTOOTHWAVE = 2
#constant TRIANGLEWAVE = 3
#constant ADSR = 4
#constant OTHER_FUNCTION = 5
#constant NOISE = 0xffff0000
#constant SAVE_FILE = 0xfffffffe
#constant LOAD_FILE = 0xffffffff
#constant MACH_1_0E70F = 1128.0
type winWAVEFORMATEX
wFormat as word
nChannels as word
nSamplesPerSec as dword
nAvgBytesPerSec as dword
nBlockAlign as word
wBitsPerSample as word
cbSize as word
endtype
type dbWAVEFORMATEX
wFormat as dword
nChannels as dword
nSamplesPerSec as dword
nAvgBytesPerSec as dword
nBlockAlign as dword
wBitsPerSample as dword
cbSize as dword
endtype
type FREQUENCY_DATA
frequency as float
amplitude as float
phase as float
endtype
type DFTPAIR
cosAmplitude as float
sinAmplitude as float
endtype
type JZWAVEOBJECT
filename as string
soundnumber as integer
timedata as JZMEMORY
frequencydata as JZMEMORY
interpolated as JZMEMORY
decimated as JZMEMORY
mean as float
stddeviation as float
snr as float
rms as float
bias as float
endtype
type CREATEWAVE
wavetype as integer
wavespec as FREQUENCY_DATA
endtype
type SINUSOIDAL_WAVE
fundamental as float rem Frequency
theta as float rem Instantaneous angle
delta as float rem Incremental rotation
amplitude as float rem Peak amplitude
endtype
#constant SINGLEENDED = 0x00000000
#constant DOUBLEENDED = 0x00000001
#constant TIMEDOMAINDATA = 0x00000002
#constant FREQUENCYDOMAINDATA = 0x00000004
#constant BITS_8 = 0x00000008
#constant BITS_16 = 0x00000010
#constant BITS_24 = 0x00000018
#constant BITS_32 = 0x00000020
#constant BITS_64 = 0x00000040
#constant RAW_DATA = 0x00000080
#constant FILTER_DATA = 0x00000100
#constant SHOW_REAL = 0x00000200
#constant SHOW_IMAG = 0x00000400
#constant FFT_ANALYSIS = 0x00000800
#constant UNBINNED_HISTOGRAM = 0x00001000
#constant BINNED_HISTOGRAM = 0x00002000
#constant DRAW_INTERSAMPLE = 0x80000000
#constant DRAW_IMPULSE = 0x40000000
type JZPOINT
x as integer
y as integer
endtype
type JZRECT
top as integer
left as integer
bottom as integer
right as integer
endtype
type JZGRAPH
name as string
rect as JZRECT
zeroline as integer
x_scale as integer
y_scale as float
color as dword
background as dword
datasize as integer
memblock as integer
offset as integer
start as integer
stop as integer
cursor as integer
mark1 as integer
mark2 as integer
min as integer
max as integer
hMarks as integer
vMarks as integer
graphflags as dword
ftemp as float
endtype
global x1 as integer
global x2 as integer
global y1 as integer
global y2 as integer
function GenerateSignal16(ptr as dword, numsamples as integer)
local integrator as integer = 0
local i as integer
local j as integer
local wtemp as word
for i = 0 to numsamples - 1
integrator = 0
for j = 0 to array count(signal())
inc integrator, int(sin(wrapvalue(signal(j).theta)) * ...
signal(j).amplitude)
inc signal(j).theta, signal(j).delta
next j
wtemp = integrator
*ptr = wtemp
inc ptr, 2
next i
endfunction
function WritePCMWaveFile(filename as string, wavedata_blk as integer, ...
size as integer)
local i as integer
local j as integer
local k as integer
local s2 as integer
local ptr as dword
ptr = get memblock ptr(wavedata_blk)
s2 = size << 1
if file exist(filename)
delete file filename
endif
open to write 1, filename
write byte 1, asc("R")
write byte 1, asc("I")
write byte 1, asc("F")
write byte 1, asc("F")
write long 1, s2 + 42
write byte 1, asc("W")
write byte 1, asc("A")
write byte 1, asc("V")
write byte 1, asc("E")
write byte 1, asc("f")
write byte 1, asc("m")
write byte 1, asc("t")
write byte 1, asc(" ")
write long 1, 16
write word 1, *ptr
inc ptr, 4
write word 1, *ptr
inc ptr, 4
write long 1, *ptr
inc ptr, 4
write long 1, *ptr
inc ptr, 4
write word 1, *ptr
inc ptr, 4
write word 1, *ptr
inc ptr, 4
write byte 1, asc("d")
write byte 1, asc("a")
write byte 1, asc("t")
write byte 1, asc("a")
write long 1, s2
for k = 0 to size - 1
write word 1, *ptr
inc ptr, 2
next k
close file 1
endfunction
function MakeSpectrumBand(frequency as float)
array insert at bottom spectrum_analysis()
spectrum_analysis().frequency = frequency
spectrum_analysis().amplitude = 0.0
spectrum_analysis().phase = 0.0
endfunction
function DoDFTSpectrumAnalysis(block as integer, pad as boolean)
local i as integer
local j as integer
local x as integer
local start as integer = 0
local enddata as integer = 0
local dataptr as dword
local datum as word
local datavalue as float
local numSamples as integer
local referenceAngle as float
local refAngleStart as float
local real as float
local imag as float
local tempreal as float
local tempimag as float
local realfrequency as float
local stupidfloat as float
start = SIZEOF_dbWAVEFORMATEX
numSamples = get memblock size(block) - start
numSamples = numSamples / memblock dword(block, _NBLOCKALIGN)
enddata = numSamples - 1
if pad = TRUE
numSamples = 1.0 * memblock dword(block, _NSAMPLESPERSEC)
endif
for i = 0 to array count(spectrum_analysis())
real = 0.0
imag = 0.0
dataptr = get memblock ptr(block)
inc dataptr, start
refAngleStart = twopi * spectrum_analysis(i).frequency
for x = 0 to numSamples - 1
stupidfloat = 1.0 * x
stupidfloat = stupidfloat / (1.0 * numSamples)
if x < enddata
datum = *dataptr
datavalue = jzMakeWordIntValue(datum) * 1.0
else
datavalue = 0.0
endif
referenceAngle = refAngleStart * stupidfloat
referenceAngle = referenceAngle * radian_convert
tempreal = datavalue * cos(referenceAngle)
tempimag = datavalue * sin(referenceAngle)
inc real, tempreal
dec imag, tempimag
inc dataptr, 2
next x
stupidfloat = sqrt((imag * imag) + (real * real))
stupidfloat = stupidfloat / MAX_VOLUME
stupidfloat = 100.0 * stupidfloat
spectrum_analysis(i).amplitude = stupidfloat
stupidfloat = atan(imag / real)
spectrum_analysis(i).phase = stupidfloat
remstart
if pad = FALSE
realfrequency = 1.0 * numSamples
realfrequency = realfrequency / 2.0
inc realfrequency, 1.0
realfrequency = realfrequency / (1.0 * array count(spectrum_analysis()))
realfrequency = realfrequency * (1.0 * i)
spectrum_analysis(i).frequency = realfrequency
endif
remend
next i
endfunction
function DoWaveFileFFT16(wavenumber as integer, start as integer, ...
length as integer)
local numbytes as integer = 0
local numsamples as integer
local source as integer = 0
local srcoffset as integer = 0
local dest as integer = 0
local i as integer = 0
local ie as integer = 0
local ie2 as integer = 0
local ip as integer = 0
local j as integer = 0
local jm1 as integer = 0
local k as integer = 0
local nm1 as integer = 0
local nd2 as integer = 0
local nd2m1 as integer = 0
local N as integer = 0
local ur as float = 0.0
local ui as float = 0.0
local sr as float = 0.0
local si as float = 0.0
local tr as float = 0.0
local ti as float = 0.0
local stages as integer = 0
local offset as integer = 0
local wtemp as word = 0
source = waves(wavenumber).timedata.memblockID
numbytes = get memblock size(source)
numsamples = numbytes - start
numsamples = numsamples >> 1
stages = jzGetMaxPowerof2(length)
N = jzPow2(stages)
nm1 = N - 1
nd2 = N >> 1
nd2m1 = nd2 - 1
k = N << 1
if waves(wavenumber).frequencydata.memblockID > 0
if memblock exist(waves(wavenumber).frequencydata.memblockID)
delete memblock waves(wavenumber).frequencydata.memblockID
endif
endif
waves(wavenumber).frequencydata.memblockID = ...
jzGetNextAvailableMemblockID(1)
make memblock waves(wavenumber).frequencydata.memblockID, k
waves(wavenumber).frequencydata.ptr = ...
get memblock ptr(waves(wavenumber).frequencydata.memblockID)
fill memory waves(wavenumber).frequencydata.ptr, 0x00, k
dest = waves(wavenumber).frequencydata.memblockID
rem Clear out arrays and redimension those that require it.
empty array fftstage()
undim fftreal()
undim fftimag()
dim fftreal(N)
dim fftimag(N)
remstart Find out the stage values for the sort. (N/2, N/4, N/8, etc.)
Stage 0 is actually N, but the algorithm is better using 1 - N
at the frequency domain synthesis portion of the routine.
remend
for i = 0 to stages - 1
array insert at bottom fftstage()
if i = 0
fftstage() = 0
else
fftstage() = N / jzPow2(i)
endif
next i
remstart The real secret of the FFT algorithm is the bit reversal sort,
which moves the data from the time domain to the frequency domain
by reordering the samples. The new order is bit reversed from the
original. This is accomplished by brute force in many of the samples
I have examined. It is also a favorite topic of programmers that are
fans of recursive programming. I always try my best to avoid using
recursion. I think that it is better to work a little longer on a
routine and come up with a better solution. In this case it really
paid off; I have a very fast routine that reorders a copy of the data
and does an FFT on it. This is the basis of any number of audio DSP
applications.
remend
for i = 0 to nd2m1
j = i << 1
offset = fftstage(0)
if i && 0x00000001
inc offset, fftstage(1)
endif
if i && 0x00000002
inc offset, fftstage(2)
endif
if i && 0x00000004
inc offset, fftstage(3)
endif
if i && 0x00000008
inc offset, fftstage(4)
endif
if i && 0x00000010
inc offset, fftstage(5)
endif
if i && 0x00000020
inc offset, fftstage(6)
endif
if i && 0x00000040
inc offset, fftstage(7)
endif
if i && 0x00000080
inc offset, fftstage(8)
endif
if i && 0x00000100
inc offset, fftstage(9)
endif
if i && 0x00000200
inc offset, fftstage(10)
endif
if i && 0x00000400
inc offset, fftstage(11)
endif
if i && 0x00000800
inc offset, fftstage(12)
endif
if i && 0x00001000
inc offset, fftstage(13)
endif
if i && 0x00002000
inc offset, fftstage(14)
endif
if i && 0x00004000 rem 65536 samples per second
inc offset, fftstage(15)
endif
if i && 0x00008000
inc offset, fftstage(16)
endif
fftimag(i) = 0.0
fftimag(nd2 + i) = 0.0
if offset < numsamples
offset = offset << 1
srcoffset = start + offset
fftreal(i) = ...
1.0 * jzMakeWordIntValue(memblock word(source, srcoffset))
fftreal(nd2 + i) = ...
1.0 * jzMakeWordIntValue(memblock word(source, srcoffset + 2))
write memblock word dest, j, memblock word(source, srcoffset)
write memblock word dest, N + j, ...
memblock word(source, srcoffset + 2)
else
fftreal(i) = 0.0
fftreal(nd2 + i) = 0.0
write memblock word dest, j, 0x0000
write memblock word dest, N + j, 0x0000
endif
next i
remstart The FFT algorithm works like many of the traditional filters used
in audio applications (analog, as well as digital) by using stages.
In some filters, the term pole is used. The DFT and other routines
gather power and phase information by running through the entire
dataset many times. The FFT does not work that way, however. After
reordering the data set, it is no longer necessary to use each
sample every time. The routine is controlled completely by the
length of the dataset and the properties of the FFT algorithm.
remend
for i = 1 to stages
ie = jzPow2(i)
ie2 = ie >> 1
ui = (pi / (1.0 * ie2)) * radian_convert
sr = cos(ui)
si = sin(ui)
ur = 1.0
ui = 0.0
for j = 1 to ie2
jm1 = j - 1
for k = jm1 to nm1 step ie
ip = k + ie2
tr = ur * fftreal(ip) - ui * fftimag(ip)
ti = ui * fftreal(ip) + ur * fftimag(ip)
fftreal(ip) = fftreal(k) - tr
fftimag(ip) = fftimag(k) - ti
fftreal(k) = fftreal(k) + tr
fftimag(k) = fftimag(k) + ti
next k
tr = ur
ur = tr * sr - ui * si
ui = tr * si + ui * sr
next j
next i
endfunction
function CreateWaveFromFile(name as string)
local iReturn as integer = -1
array insert at bottom waves()
waves().filename = name
waves().soundnumber = jzGetNextAvailableSoundID(1)
load sound waves().filename, waves().soundnumber
waves().timedata.memblockID = jzGetNextAvailableMemblockID(1)
make memblock from sound waves().timedata.memblockID, ...
waves().soundnumber
waves(currentwave).timedata.ptr = ...
get memblock ptr(waves().timedata.memblockID)
waves().frequencydata.memblockID = 0
waves().frequencydata.ptr = NULL
waves().interpolated.memblockID = 0
waves().interpolated.ptr = NULL
waves().decimated.memblockID = 0
waves().decimated.ptr = NULL
waves().mean = 0.0
waves().stddeviation = 0.0
waves().snr = 0.0
waves().rms = 0.0
waves().bias = 0.0
iReturn = array count(waves())
GetWaveStatistics(iReturn)
endfunction iReturn
function GetWaveSampleTime(wave as integer, samplenumber as integer)
local sampletime as float = 0.0
if wave <= array count(waves())
sampletime = 1.0 * memblock word(waves(wave).timedata.memblockID, ...
_NSAMPLESPERSEC)
if samplenumber > 0
sampletime = 1.0 * samplenumber / sampletime
endif
endif
endfunction sampletime
function GetWaveStatistics(wave as integer)
local i as integer = 0
local j as integer = 0
local ptr as dword = 0
local numsamples as integer = 0
local total as float = 0.0
local totalexcursion as float = 0.0
local ftemp as float = 0.0
local ftemp2 as float = 0.0
local variance as float = 0.0
if wave <= array count(waves())
numsamples = get memblock size(waves(wave).timedata.memblockID) - ...
SIZEOF_dbWAVEFORMATEX
numsamples = numsamples >> 1
ptr = waves(wave).timedata.ptr
inc ptr, SIZEOF_dbWAVEFORMATEX
for i = 0 to numsamples - 1
ftemp = 1.0 * jzMakeWordIntValue(*ptr)
inc totalexcursion, ftemp
inc total, abs(ftemp)
inc ptr, 2
next i
ftemp2 = 1.0 * numsamples
ftemp = total / ftemp2
waves(wave).mean = ftemp
ftemp = totalexcursion / ftemp2
waves(wave).bias = ftemp
variance = 0.0
ptr = waves(wave).timedata.ptr
inc ptr, SIZEOF_dbWAVEFORMATEX
for i = 0 to numsamples - 1
ftemp = 1.0 * abs(jzMakeWordIntValue(*ptr))
dec ftemp, waves(wave).mean
inc variance, ftemp * ftemp
inc ptr, 2
next i
dec ftemp2, 1.0
variance = variance / ftemp2
waves(wave).stddeviation = sqrt(variance)
waves(wave).snr = waves(wave).mean / waves(wave).stddeviation
undim histogram()
dim histogram(jzPow2(16))
for i = 0 to jzPow2(16) - 1
histogram(i) = 0
next i
j = 0
for i = 0 to numsamples - 1
inc histogram(memblock word(waves(wave).timedata.memblockID, j)), 1
inc j, 2
next i
j = 0
for i = 0 to jzPow2(16) - 1
if histogram(i) <> 0
inc j, 1
endif
next i
endif
endfunction
function GetMaxHistogramBinValue()
local i as integer = 0
local j as integer = 0
for i = 0 to array count(histogram()) - 1
if histogram(i) > j
j = histogram(i)
endif
next i
endfunction j
function DecimateWave(wave as integer, newrate as integer)
rem
endfunction
function InterpolateWave(wave as integer, newrate as integer)
rem
endfunction
function MixWaves(wave1 as integer, wave2 as integer, ratio as float, ...
method as integer)
local iReturn as integer = -1
array insert at bottom waves()
waves().filename = "tempmix.wav"
waves().soundnumber = -1
waves().timedata.memblockID = -1
waves(currentwave).timedata.ptr = NULL
waves().frequencydata.memblockID = 0
waves().frequencydata.ptr = NULL
waves().interpolated.memblockID = 0
waves().interpolated.ptr = NULL
waves().decimated.memblockID = 0
waves().decimated.ptr = NULL
waves().mean = 0.0
waves().stddeviation = 0.0
waves().snr = 0.0
waves().rms = 0.0
waves().bias = 0.0
iReturn = array count(waves())
rem GetWaveStatistics(iReturn)
endfunction iReturn
function GetSamplesPerBaud(sps as integer, bps as integer)
local samples as float
local baud as float
local samplesperbaud as float
local ireturn as integer
samples = 1.0 * sps
baud = 1.0 * bps
samplesperbaud = samples / baud
ireturn = int(samplesperbaud)
endfunction ireturn
function DSPShutdown()
local i as integer
for i = 0 to array count(waves())
if waves(i).timedata.memblockID > 0
if memblock exist(waves(i).timedata.memblockID)
delete memblock waves(i).timedata.memblockID
endif
endif
if waves(i).frequencydata.memblockID > 0
if memblock exist(waves(i).frequencydata.memblockID)
delete memblock waves(i).frequencydata.memblockID
endif
endif
if waves(i).interpolated.memblockID > 0
if memblock exist(waves(i).interpolated.memblockID)
delete memblock waves(i).interpolated.memblockID
endif
endif
if waves(i).decimated.memblockID > 0
if memblock exist(waves(i).decimated.memblockID)
delete memblock waves(i).decimated.memblockID
endif
endif
if sound exist(waves(i).soundnumber)
delete sound waves(i).soundnumber
endif
next i
empty array waves()
empty array spectrum_analysis()
endfunction
function GetMaxYScale(value as integer, numpixels as integer)
local maxscale as float
local ival as float
local inumpixels as float
ival = 1.0 * value
inumpixels = 1.0 * numpixels
if inumpixels > ival
maxscale = inumpixels / ival
else
maxscale = 1.0 / (ival / inumpixels)
endif
endfunction maxscale
function GetGraphCursorTime(graph as integer)
local timef as float = 0.0
if graph <= array count(graphs())
timef = GetWaveSampleTime(0, (graphs(graph).cursor - ...
graphs(graph).start) >> 1)
endif
endfunction timef
function PlotNextGraphPage(graph as integer)
if graph <= array count(graphs())
graphs(graph).offset = PlotGraph(graph)
endif
endfunction
function PlotPreviousGraphPage(graph as integer)
if graph <= array count(graphs())
if graphs(graph).offset < screen_width * 4
graphs(graph).offset = graphs(graph).start
else
graphs(graph).offset = graphs(graph).offset - screen_width * 4
endif
graphs(graph).offset = PlotGraph(graph)
endif
endfunction
function ToggleGraphState(graph as integer, state as dword)
if graph <= array count(graphs())
graphs(graph).graphflags = graphs(graph).graphflags ~~ state
i = PlotGraph(graph)
endif
endfunction
function IncrementGraphCursorPosition(graph as integer)
local i as integer
if graph <= array count(graphs())
inc graphs(graph).cursor, graphs(graph).datasize
if graphs(graph).cursor > graphs(graph).stop
graphs(graph).cursor = graphs(graph).stop
endif
i = PlotGraph(graph)
endif
endfunction
function DecrementGraphCursorPosition(graph as integer)
local i as integer
if graph <= array count(graphs())
dec graphs(graph).cursor, graphs(graph).datasize
if graphs(graph).cursor < graphs(graph).start
graphs(graph).cursor = graphs(graph).start
endif
i = PlotGraph(graph)
endif
endfunction
function IncrementGraphXScale(graph as integer)
if graph <= array count(graphs())
inc graphs(graph).x_scale, 1
if graphs(graph).x_scale >= mid_x
graphs(graph).x_scale = mid_x
endif
i = PlotGraph(graph)
endif
endfunction
function DecrementGraphXScale(graph as integer)
if graph <= array count(graphs())
dec graphs(graph).x_scale, 1
if graphs(graph).x_scale < 1
graphs(graph).x_scale = 1
endif
i = PlotGraph(graph)
endif
endfunction
function PointInRect(pt as JZPOINT, graph as integer)
local inrect as boolean
if graph <= array count(graphs())
inrect = FALSE
if pt.x >= graphs(graph).rect.left and ...
pt.x <= graphs(graph).rect.right and ...
pt.y >= graphs(graph).rect.top and ...
pt.y <= graphs(graph).rect.bottom
inrect = TRUE
endif
endif
endfunction inrect
function PlotGraph(plotgraph as integer)
local x1 as integer
local x2 as integer
local y1 as integer
local y2 as integer
local offset as integer
local linesize as integer = 2
local samplecolor as dword = 0x00000000
local ptr as dword
local datum as word
local datavalue as float
local i as integer
if plotgraph <= array count(graphs())
ink graphs(plotgraph).background, 0
box graphs(plotgraph).rect.left, graphs(plotgraph).rect.top, ...
graphs(plotgraph).rect.right, graphs(plotgraph).rect.bottom
x1 = graphs(plotgraph).rect.left
y1 = graphs(plotgraph).zeroline
ink rgb(255, 255, 255), 0
set cursor graphs(plotgraph).rect.left, graphs(plotgraph).rect.top
print graphs(plotgraph).name
line x1, graphs(plotgraph).zeroline, graphs(plotgraph).rect.right, y1
ink rgb(192, 192, 192), 0
line graphs(plotgraph).rect.left, graphs(plotgraph).rect.top, ...
graphs(plotgraph).rect.right, graphs(plotgraph).rect.top
line graphs(plotgraph).rect.left, graphs(plotgraph).rect.bottom, ...
graphs(plotgraph).rect.right, graphs(plotgraph).rect.bottom
ink graphs(plotgraph).color, 0
if graphs(plotgraph).graphflags && DOUBLEENDED
x1 = graphs(plotgraph).rect.left
y1 = graphs(plotgraph).zeroline
offset = graphs(plotgraph).offset
if graphs(plotgraph).memblock > 0
ptr = get memblock ptr(graphs(plotgraph).memblock)
if offset >= graphs(plotgraph).stop
dec offset, graphs(plotgraph).datasize
endif
inc ptr, offset
datum = *ptr
datavalue = 1.0 * jzMakeWordIntValue(datum)
dec y1, datavalue * graphs(plotgraph).y_scale
inc ptr, graphs(plotgraph).datasize
endif
for i = graphs(plotgraph).rect.left to graphs(plotgraph).rect.right step graphs(plotgraph).x_scale
if graphs(plotgraph).graphflags && RAW_DATA
if offset >= graphs(plotgraph).stop
datavalue = 0.0
else
datum = *ptr
datavalue = 1.0 * jzMakeWordIntValue(datum)
if offset = graphs(plotgraph).cursor
samplecolor = rgb(255, 255, 0)
linesize = 4
endif
inc offset, graphs(plotgraph).datasize
inc ptr, graphs(plotgraph).datasize
endif
endif
x2 = x1 + graphs(plotgraph).x_scale
y2 = graphs(plotgraph).zeroline - (datavalue * graphs(plotgraph).y_scale)
if graphs(plotgraph).graphflags && DRAW_INTERSAMPLE
line x1, y1, x2, y2
endif
if graphs(plotgraph).graphflags && DRAW_IMPULSE
ink rgb(0, 255, 0), 0
line x2, graphs(plotgraph).zeroline, x2, y2
endif
ink samplecolor, 0
line x2 - linesize, y2, x2 + linesize, y2
line x2, y2 - linesize, x2, y2 + linesize
if linesize = 4
circle x2, y2, 6
endif
samplecolor = 0x00000000
linesize = 2
x1 = x2
y1 = y2
ink graphs(plotgraph).color, 0
next i
if offset >= graphs(plotgraph).stop
offset = graphs(plotgraph).start
endif
ink rgb(255, 255, 255), 0
print "Mean: " + str$(waves(0).mean, 3) + ...
" | stddev: " + str$(waves(0).stddeviation, 3) + ...
" | SNR: " + str$(waves(0).snr, 3) + " : 1" + " | bias: " + ...
str$(waves(0).bias, 3) + " | sample#: " + ...
str$((graphs(plotgraph).cursor - SIZEOF_dbWAVEFORMATEX) >> 1) + ...
" | time: " + str$(GetGraphCursorTime(plotgraph), 6)
else
if graphs(plotgraph).graphflags && FREQUENCYDOMAINDATA
if graphs(plotgraph).graphflags && SHOW_REAL
for i = graphs(plotgraph).start to graphs(plotgraph).stop
x2 = x1 + graphs(plotgraph).x_scale
y2 = graphs(plotgraph).zeroline - ...
(spectrum_analysis(i).amplitude * graphs(plotgraph).y_scale)
line x1, y1, x2, y2
x1 = x2
y1 = y2
next i
else
if graphs(plotgraph).graphflags && SHOW_IMAG
for i = graphs(plotgraph).start to graphs(plotgraph).stop
x2 = x1 + graphs(plotgraph).x_scale
y2 = graphs(plotgraph).zeroline + ...
(spectrum_analysis(i).phase * graphs(plotgraph).y_scale)
line x1, y1, x2, y2
x1 = x2
y1 = y2
next i
endif
endif
print "DC Bias:" + str$(spectrum_analysis(0).amplitude, 3)
else
if graphs(plotgraph).graphflags && FFT_ANALYSIS
for i = graphs(plotgraph).start to graphs(plotgraph).stop
x2 = x1 + graphs(plotgraph).x_scale
datavalue = 2.0 * ...
sqrt((fftreal(i) * fftreal(i)) + ...
(fftimag(i) * fftimag(i)))
datavalue = datavalue / MAX_VOLUME
datavalue = datavalue * 100.0
y2 = graphs(plotgraph).zeroline - ...
(datavalue * graphs(plotgraph).y_scale)
line x1, y1, x2, y2
x1 = x2
y1 = y2
next i
datavalue = 2.0 * ...
sqrt((fftreal(0) * fftreal(0)) + ...
(fftimag(0) * fftimag(0)))
print "DC Bias:" + str$(datavalue)
else
if graphs(plotgraph).graphflags && UNBINNED_HISTOGRAM
y1 = graphs(plotgraph).zeroline
x1 = graphs(plotgraph).rect.left
offset = graphs(plotgraph).offset
print "Histogram: " + str$(offset)
for i = graphs(plotgraph).rect.left to graphs(plotgraph).rect.right
if offset >= graphs(plotgraph).datasize
exit
endif
y2 = y1 - (histogram(offset) * graphs(plotgraph).y_scale)
line x1, y1, x1, y2
inc x1, 1
inc offset, 1
next i
if offset >= graphs(plotgraph).datasize
offset = 0
endif
endif
endif
endif
endif
ink rgb(255, 0, 0), 0
for i = graphs(plotgraph).rect.left to graphs(plotgraph).rect.right
if i mod graphs(plotgraph).hMarks = 0
line i, graphs(plotgraph).zeroline - 4, i, graphs(plotgraph).zeroline
endif
next i
endif
endfunction offset