Using+SOUND+with+true+frequencies

//by Richard Russell, May 2014//

The [|SOUND] statement's third parameter normally specifies the required **pitch** in units of quarter-semitones. For example the value 100 corresponds to **middle C** and the value 136 corresponds to the **A above middle C** (440 Hz, the standard musical pitch).

Steps of ¼ semitone will normally be sufficiently fine, even for //glissando// or //vibrato// effects, but occasionally it may be useful to specify the pitch more precisely, in terms of a frequency in **Hertz**. For example if one prefers to use [|just intonation] rather than an equally-tempered scale it would be preferable to approximate the frequencies as accurately as possible (in practice BB4W provides a resolution of approximately one-third Hz).

The function **FNfreqout** listed below makes this possible. It takes as a parameter the required frequency in Hz (the maximum being around 10 kHz, but at frequencies that high aliasing effects can be excessive) and returns a value which should be specified as the third parameter of the SOUND statement.

Here is an example program illustrating its use: code format="bb4w" FOR freq = 500 TO 1000 SOUND 1, -15, FNfreqout(freq), 1 NEXT END

DEF FNfreqout(f) LOCAL I% : PRIVATE ftab%, indx& IF ftab% = 0 THEN LOCAL base% SYS "GetModuleHandle", 0 TO base% FOR I% = base% TO base% + 65534 STEP 2 IF !I% = &03550354 IF I%!4 = &06060606 EXIT FOR NEXT IF I% > base% + 65534 ERROR 100, "Cannot locate frequency table" ftab% = I% + 8 SYS "VirtualProtect", ftab% AND -&1000, &2000, &40, ^I% TO I%       IF I% = 0 ERROR 100, "Cannot make memory image writable" ENDIF indx& += 1 : IF indx& = 0 indx& = 1 I% = 2 * indx& ftab%!I% = ftab%!I% AND &FFFF0000 OR INT(f * &10000 / 22050 + 0.5) = indx& code A limitation of this technique is that a maximum of **255** different frequencies can be 'active' at once. If **FNfreqout** is called more than that number of times the oldest frequencies will be overwritten. If an **ENVELOPE** statement is used it should not contain a pitch component (at least, not unless special measures are taken); amplitude envelopes work as expected.

Note that **FNfreqout** works by dynamically rewriting BBC BASIC's frequency table, so if used in a program run from the BB4W **IDE** subsequent programs which use the SOUND statement may be affected. If in doubt quit //BBC BASIC for Windows// and restart it. This issue does not affect its use in a 'compiled' program.