This program displays a real-time spectrum of whatever audio signal is fed to your PC (microphone input or line input, as selected in Windows Volume Control). The .EXE version is self-contained, but if you want to run the .BBC version you will need to download FFTW2DLL.DLL to your BBC BASIC for Windows\LIB folder.
Download ANALYSER.BBC | Run ANALYSER.EXE |
---|
REM. Real-time audio spectrum analyser in BBC BASIC for Windows
REM. Richard Russell, 20th November 2006
*FLOAT 64
MODE 8
OFF
ON ERROR PROCcleanup : SYS "MessageBox", @hwnd%, REPORT$, 0, 48 : QUIT
ON CLOSE PROCcleanup : QUIT
REM. Install 'Fastest Fourier Transform in the West' DLL:
SYS "LoadLibrary", @lib$+"FFTW2DLL.DLL" TO fftw%
IF fftw% = 0 ERROR 100, "Cannot load FFTW2DLL.DLL"
SYS "GetProcAddress", fftw%, "fftw_create_plan" TO `fftw_create_plan`
SYS "GetProcAddress", fftw%, "fftw_one" TO `fftw_one`
REM. Open wave input device:
DIM Format{wFormatTag{l&,h&}, nChannels{l&,h&}, nSamplesPerSec%, \
\ nAvgBytesPerSec%, nBlockAlign{l&,h&}, wBitsPerSample{l&,h&}, \
\ cbSize{l&,h&}}
Format.wFormatTag.l& = 1 : REM WAVE_FORMAT_PCM
Format.nChannels.l& = 1 : REM Monaural
Format.nSamplesPerSec% = 11025
Format.wBitsPerSample.l& = 16
Format.nBlockAlign.l& = Format.nChannels.l& * Format.wBitsPerSample.l& / 8
Format.nAvgBytesPerSec% = Format.nSamplesPerSec% * Format.nBlockAlign.l&
_WAVE_MAPPER = -1
SYS "waveInOpen", ^WaveIn%, _WAVE_MAPPER, Format{}, 0, 0, 0 TO ret%
IF ret% ERROR 100, "waveInOpen failed: "+STR$~ret%
REM. Create wave headers:
DIM _WAVEHDR{lpData%, dwBufferLength%, dwBytesRecorded%, dwUser%, \
\ dwFlags%, dwLoops%, lpNext%, Reserved%}
nBuffers% = 3
DIM Headers{(nBuffers%-1)}=_WAVEHDR{}
REM. Fill in wave headers; allocate, prepare and add buffers:
SamplesPerBuffer% = 1024
BytesPerBuffer% = SamplesPerBuffer% * Format.nBlockAlign.l&
FOR buff% = 0 TO nBuffers%-1
DIM buffer% BytesPerBuffer% - 1
Headers{(buff%)}.lpData% = buffer%
Headers{(buff%)}.dwBufferLength% = BytesPerBuffer%
SYS "waveInPrepareHeader", WaveIn%, Headers{(buff%)}, !!^_WAVEHDR{} TO ret%
IF ret% ERROR 100, "waveInPrepareHeader failed: "+STR$~ret%
SYS "waveInAddBuffer", WaveIn%, Headers{(buff%)}, !!^_WAVEHDR{} TO ret%
IF ret% ERROR 100, "waveInAddBuffer failed: "+STR$~ret%
NEXT
REM. Prepare FFT:
_FFTW_FORWARD = -1
SYS `fftw_create_plan`, SamplesPerBuffer%, _FFTW_FORWARD, 0 TO Plan%
IF Plan%=0 ERROR 100, "fftw_create_plan failed"
DIM In#(SamplesPerBuffer%-1,1), Out#(SamplesPerBuffer%-1,1)
REM. Draw axes and labels:
ORIGIN 128,64
LINE -2,-2,-2,903 : REM Y-axis
LINE -2,-2,1022,-2 : REM X-axis
VDU 5
FOR F = 0 TO 5
X% = F/5.5125*1024
LINE X%-2,-2,X%-2,-12 : REM X ticks
MOVE X%-10,-20 : PRINT ;F*Format.nSamplesPerSec%/11025; : REM X labels
NEXT
PRINT " kHz";
FOR D = 0 TO -90 STEP -10
Y% = 903 + D*10
LINE -2,Y%-2,-12,Y%-2 : REM Y ticks
MOVE -80,Y%+12 : PRINT ;D; : REM Y labels
IF D = 0 PRINT " dB";
NEXT
COLOUR 1,100,255,100
GCOL 1
VDU 28,8,29,71,0 : REM Set text viewport
VDU 24,0;0;1022;958; : REM Set graphics viewport
REM. Start capture:
SYS "waveInStart", WaveIn% TO ret%
IF ret% ERROR 100, "waveInStart failed: "+STR$~ret%
*REFRESH OFF
REM. Wait for and process audio data:
_WHDR_DONE = 1
REPEAT
FOR buff% = 0 TO nBuffers%-1
IF Headers{(buff%)}.dwFlags% AND _WHDR_DONE THEN
PROCprocess(Headers{(buff%)}.lpData%,SamplesPerBuffer%)
Headers{(buff%)}.dwFlags% AND= NOT _WHDR_DONE
SYS "waveInAddBuffer", WaveIn%, Headers{(buff%)}, !!^_WAVEHDR{}
ENDIF
NEXT
SYS "Sleep", 1
UNTIL FALSE
END
DEF PROCcleanup
*REFRESH ON
WaveIn% += 0 : IF WaveIn% THEN
SYS "waveInStop", WaveIn%
SYS "waveInReset", WaveIn%
SYS "waveInClose", WaveIn%
WaveIn% = 0
ENDIF
fftw% += 0 : IF fftw% SYS "FreeLibrary", fftw% : fftw% = 0
ENDPROC
REM. Process data in audio buffer: n.b. time-critical!
DEF PROCprocess(B%,N%)
LOCAL I%, P%, V%, V, L
FOR I% = 0 TO N%-1
V% = B%!(I%*2) AND &FFFF : IF V% >= &8000 V% -= 65536
In#(I%,0) = V%/N% * (COS((I%/N%-0.5)*PI*2)+1) : REM Hanning window
NEXT
In#() *= 2.0
SYS `fftw_one`, Plan%, ^In#(0,0), ^Out#(0,0)
CLS
P% = 4
FOR I% = 0 TO N%/2-1
V = Out#(I%,0)^2+Out#(I%,1)^2
IF V=0 L=0 ELSE L=10*LOGV
PLOT P%,I%*2,L*10 : P%=5
NEXT
*REFRESH
ENDPROC