drew
|
|
Wave-by-wave manipulation of PC speaker
|
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?
|
drew
|
|
response 4 of 6:
|
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:
|
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.
|