Home Page

R. T. RUSSELL

BBC BASIC for Windows

Audio Spectrum Analyser



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 PROC
cleanup : SYS "MessageBox", @hwnd%, REPORT$, 0, 48 : QUIT
     ON CLOSE PROC
cleanup : 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
           PROC
process(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


Home - Products - Contact us

Best viewed with Any Browser Valid HTML 3.2!
© Richard Russell 2006