Computer music on the radio

If you listen to an AM radio that’s placed near a computer, you can hear interference. I can put my radio next to my tablet and hear all the calculations being done as my ink handwriting is being converted to text.

The AM frequency range is from 530 to 1710 khz. My Junior High and High School computer (Relaxen und watchen das blinkenlights. What lights?) had a 1.5 µsecond cycle time, or 660 Khz which is right in the middle of the AM band.

Because the PDP-8 had only one general register, called the accumulator, and had only one thread of execution, it was easy to write programs to flash the accumulator at various frequencies that could directly generate tones on an AM Radio. Because sound waves can pass through each other and continue on (wave superposition), making the computer play two notes at once was just trigonometry.

Below is some code to demonstrate. It draws 2 sine waves in red and the sum of those 2 in blue. Initially, the phase difference between them is 0 degrees, so it appears that there is only 1 wave. The slider changes the relative frequencies of the 2 waves. It’s initial value of 0 means they are the same frequency. The spinner changes the phase difference between the 2. You can change the phase to 180 degrees with the frequencies the same, and see the signals sum to 0. (I guess that’s how noise canceling headphones work they generate a signal that’s 180 degrees out of phase with the ambient noise.)

As the frequency difference gets large, you can see the sum taking on the shape of the lower frequency wave. This is similar to how FM radio works: the high frequency wave is modulated by the broadcast signal and the low frequency wave is the FM frequency (from 87.5 Mhz to 108 Mhz). (For how black & white TV works on the same signal as color, see Why was the original IBM PC 4.77 Megahertz?)

You can get fancy and add controls for the relative amplitudes of the waves.

PUBLIC ox

ox=CREATEOBJECT("signalform")

ox.show

DEFINE CLASS signalform as form

      width=800

      height=300

      left=300

      backcolor=0xffffff

      allowoutput=.f.

      ADD OBJECT spn as spinner WITH left=130,;

            SelectOnEntry=.t.,;

            SpinnerLowValue=0,;

            SpinnerHighValue=360,;

            Increment=10,;

            value=0

      PROCEDURE init

            this.AddObject("oSlider","MySlider")

            WITH this.oSlider

                  .min=-100

                  .max=100

                  .SmallChange=5 && a penny

                  .Value=0

                  .visible=1

            ENDWITH

      PROCEDURE keypress(nKeyCode, nShiftAltCtrl)

            DO case

            CASE nKeyCode=27 && escape

                  thisform.release

            ENDCASE

      PROCEDURE activate

            thisform.DrawWaves

      PROCEDURE DrawWaves

            nWaves=2

            nTheta= thisform.spn.Value*PI()/180

            nFactor=thisform.oSlider.Value/100

            thisform.Cls

            thisform.Caption=TRANSFORM(nFactor)+" "+TRANSFORM(nTheta)

            DIMENSION aFreq[nWaves],ay[nWaves]

            FOR i = 1 TO nWaves

                  aFreq[i]=1+(i-1)*nFactor

            ENDFOR

            yMax=thisform.Height/4/nWaves

            yOffset=thisform.Height/2 && x axis halfway down

            thisform.Line(0,yOffset,thisform.Width,yOffset) && draw x axis

            xMax=thisform.Width

            FOR x =1 TO xMax

                  y=0

                  this.ForeColor=RGB(255,0,0)

                  FOR i=1 TO nWaves

                        yp=- yMax*SIN(2*PI()*aFreq[i]*x/100+(i-1)*nTheta)

                        thisform.PSet(x,yp+yOffset)

                        y= y +yp

                  ENDFOR

                  this.ForeColor=RGB(0,0,255)

                  thisform.PSet(x,y+yOffset)

            ENDFOR

      PROCEDURE spn.InteractiveChange

            thisform.DrawWaves

ENDDEFINE

DEFINE CLASS MySlider as olecontrol

      oleclass="MSComctllib.slider.2"

      PROCEDURE Change

            thisform.DrawWaves

      PROCEDURE keypress(nKeyCode, nShiftAltCtrl)

            thisform.keypress(nKeyCode, nShiftAltCtrl)

ENDDEFINE