You are not logged in. Login Now
 0-6          
 
Author Message
drew
Wave-by-wave manipulation of PC speaker Mark Unseen   Jul 8 22:36 UTC 1997

There are a couple of routines whereby the speaker in a PC can be made to
produce a tone; you output to a port numbers corresponding to a frequency and
a duration, and the tone is generated automatically.

* This is NOT what I am after. *

What I need is information on setting the *voltage level* across the leads
of the speaker, to produce tones on a wave-by-wave basis. To wit, code looking
something like

        for (w=0; w < NUM_OF_WAVES; w++) {
                set_speaker_voltage(HIGH);
                wait(MICROSECONDS);
                set_speaker_voltage(LOW);
                wait(MICROSECONDS);
        }

should generate NUM_OF_WAVES wavelengths duration of a tone of frequency 
1 / (2 * MICROSECONDS) MHz, or as close as the hardware is capable to getting.

Can anyone help in writing set_speaker_voltage()? Also, how many different
voltage levels can the speaker be set to?
6 responses total.
n8nxf
response 1 of 6: Mark Unseen   Jul 9 10:46 UTC 1997

I suspect, none.  The oscillator the drives the PC speaker is of the square
wave variety that divides down a (10 MHz?) clock to produce an audible tone.
The only command you can send the to the PC speaker is basically "N", the
No. to divide the clock by.  You can't control the voltage to the speaker.
I suspect it is set to 5v in most PCs.
drew
response 2 of 6: Mark Unseen   Jul 9 22:56 UTC 1997

It almost has to be possible. I have a program which converts typed text into
speach coming out of the speaker (NOT a sound card). There are also touch-tone
phone tone generators for the PC, also using the speaker. Sending frequency-
and-duration commands via the frequency divider simply cannot be done fast
enough even in assembly language to handle such tasks. Or can it? I think
I've tried at least once to produce varying tones, and the machine was just
too slow at switching them.
n8nxf
response 3 of 6: Mark Unseen   Jul 10 12:28 UTC 1997

I thougughght you wanted to control not only the frequency but the amplitude
(volume) of  the frequency?  As far as I know, you can't control the volume.
drew
response 4 of 6: Mark Unseen   Jul 10 23:58 UTC 1997

That depends on how many bits "wide" the control to the speaker is. If there
is only one bit controlling the voltage, then correct, the amplitude is fixed,
and only a square wave of one frequency at6 a time would be possible. With
two bits for speaker level, there would be either 3 or 4 possible levels,
depending on whether 0,1 produces the same voltage as 1,0; and then it would
be possible to generate a dual-tone signal by switching one bit at one
frequency and the other bit at another frequency.

However, even single-bit control might suffice, *IF* there is a way to
directly control the bit itself, rather than depend on the frequency-divider
chip to do the work (which it seems unable to do quickly enough).
srw
response 5 of 6: Mark Unseen   Jul 12 17:39 UTC 1997

I did this 22 years ago in 1975, so I suspect it is still possible. At the
time, I had an IMSAI 8080 and D->A converter. It was crude by today's
standards, but I could write to it every 5 us or so, so it could generate high
enough tones, although the CPU wasn't up to that. 

I coded the inner loop and could write to it about every 40 to 45 us,
which sets an upper limit of about 12.5 khz. 

The width was 8 bits, so I could set any level from -128 to 127. This is way
inadequate for dynamic range, but I certainly could change the volume.

What I did as far as coding it was something like this:

I built a wavetable, which is just an array of voltage levels. This array
should describe a full wave, and determines the timbre of the tone. For speed
you might want to scale it in a temp array to produce the volume you want.
I did not address "attacks" or "envelopes" which are needed to compete with
what modern synthesizers can do. I just didn't have the hardware to do this.

Then you want to set the pitch. This is handled by logic in the main loop.
The main loop consists of picking an entry out of the wave table and then
setting the D2A device to its value. You want to come through this loop at
extremely regular intervals. In the loop, you have code like this

phase+= pitch;
if (phase >= LIMIT) phase-= LIMIT;
index= (WAVETABLESIZE*phase)/LIMIT;
writeD2A(WaveTable[index]);

I am assuming these are all ints. 
WAVETABLESIZE is the number of entries in your wave table. If it is too small,
your waves will not be smooth.

LIMIT is a large number, because it is
essentially the scale factor for phase. phase/LIMIT as an integer is always
0, because phase is always < LIMIT. 

However, LIMIT*WAVETABLESIZE must be less than MAXINT, so you have to juggle 
here. You need at least 32 bit aritmetic. If you have a fast FPU, use it.

When I used that old 8080, I skipped the multiplies and divides and did 
it all with shifting. The concepts are the same. It's faster, but less general,
and if you assume as I did that I could just let it overflow and AND off the 
sign bit, it becomes faster yet, but less portable.A

Higher pitch causes it to cycle through the waves faster. 

I actually had 6 voices calculated simultaneously, and added three together for
each speaker, producing stereo 6-part harmonies. The tone quality sucked, 
though, because I was using a digital computer to emulate what analog circuitry
can do so much better. This was an interesting exercise, but not anything to
produce decent music. 

Of course on computers of today, much better results could be obtained. 
Remember, though, that producing tones this way is real-time programming.
You don't have time to do anything else with the computer while it is
doing this.

Modern synthesizers are the tops. I would do it with MIDI today.
drew
response 6 of 6: Mark Unseen   Jul 12 19:34 UTC 1997

I did similar work using the cassette output port on a TRS-80. The control
port was two bits wide, so it was possible to switch one of the bits back and
forth at one frequency and the other bit back and forth at another frequency
to generate a dual-tone signal. In spite of it being square waves, it worked
amazingly well.

I want to do something similar on an Intel-based PC.
 0-6          
Response Not Possible: You are Not Logged In
 

- Backtalk version 1.3.30 - Copyright 1996-2006, Jan Wolter and Steve Weiss