I know of two ways of achieving polyphony in system with 1-bit audio systems:
- The simple way: time-multiplex two or more frequencies. For example, if you want the system to produce a mix of two tones, which are pure square waves in origin like these:

you can simply render a period of first tone, followed by a period of second tone, and again, a period of first tone...

This method limits your tones to be just pure frequencies, and if a very low frequency tone is to be mixed with a very high frequency one, the result is not very good. Nevertheless, this method works fine for simple tunes which may have some simple chords (such as the kind of tunes you can achieve using the PLAY command in a Spectrum 128K)
- The PWM way: this uses a modulation technique called PWM, which allows a 1-bit output driver to generate any complex sound, by varying the duty cycle of a very high fixed frequency tone. The frequency of the PWM signal is then the sampling period of a digital signal, and the number of different values the duty cycle can have is the resolution of that digital signal. For example, a PWM signal with a frequency of 10kHz and with 16 possible levels for duty cycle can encode a 4-bit digital signal with a sampling frequency of 10kHz.
There is an implementation of PWM that allows for fast operation, called sigma-delta modulation. I wrote some PoC programs for the Spectrum to illustrate this method. There is a thread in WOS discussing the matter, with some programs you can actually load and hear. One of them I provide it with full source code.
It works as follows: first, I take a raw PCM sound and use sigma-delta modulation to convert it into a stream of bits, each of them being the actual output to put in the speaker
/*
Offline conversion of 8-bit sample files (RAW format, no header) to
1-bit sigma-delta encoded stream files.
(C)2012 Miguel Angel Rodriguez Jodar (mcleod_ideafix)
Dept. Architecture and Computer Technology. University of Seville, Spain
Licensed under the terms of GPL.
Change input and output files to suit your needs.
TO-DO: process input file in chunks, rather than completely load it in memory
*/
#define INPUTFILE "yeaaaah.raw"
#define OUTPUTFILE "yeahh4bit_sigma_delta.bin"
#include <stdio.h>
#include <stdlib.h>
void main (void)
{
FILE *f;
int leido;
int i,sample,integrador,salida,filesize;
unsigned char *buffer; /* remove "unsigned" if using signed samples */
unsigned char *buffout;
f=fopen (INPUTFILE, "rb");
fseek (f, 0, SEEK_END);
filesize = ftell (f);
fseek (f, 0, SEEK_SET);
buffer=malloc(filesize);
buffout=malloc(filesize/4);
filesize = fread (buffer, 1, filesize, f);
fclose(f);
integrador = 0;
salida = 0;
memset (buffout, 0, filesize/4);
for (i=0;i<filesize;i++)
{
sample = buffer[i]-128; /* remove -128 if using signed samples */
integrador += (sample-salida);
if (integrador>0)
{
salida=127;
buffout[i/4] = buffout[i/4] | (1<<(7-(i*2)%8));
}
else
{
salida=-128;
}
/* repeat once (2x oversampling) */
integrador += (sample-salida);
if (integrador>0)
{
salida=127;
buffout[i/4] = buffout[i/4] | (1<<(7-(i*2+1)%8));
}
else
{
salida=-128;
}
}
f=fopen (OUTPUTFILE, "wb");
fwrite (buffout, 1, filesize/4, f);
fclose(f);
free(buffer);
free(buffout);
}
Then, the stream of bits are simply played by a machine code routine.
; Simple player for 1-bit samples. See file 8tosigmadelta.c for sigma-delta
; offline conversion of 8-bit sample files to 1-bit sample files.
; (C)2012 Miguel Angel Rodriguez Jodar. (mcleod_ideafix)
; Dept. of Architecture and Computing Technology. University of Seville, Spain
; Licensed under the terms of GPL.
; Assembled using PASMO.
org 49152
BORDERCOLOUR equ 7
DemoPlaySample proc
ld hl,Sample
ld de,LenSample
call PlaySample
ret
endp
PlaySample proc
di
AnotherSample: ld a,(hl) ;Load 8 samples
ld b,8
LoopSample: ld c,a ;Backup to C
and 80h ;Isolate high bit
sra a
sra a
sra a ;Shift it to SPK bit
or BORDERCOLOUR ;Apply desired border colour
out (254),a ;Output to spk
ld a,c ;Restore from C
rla ;Next sample is now in high bit
nop ;
nop ; Delay
nop ;
nop ;
djnz LoopSample ;Go to process next sample
inc hl
dec de
ld a,d
or e
jp nz,AnotherSample ;Go to process next 8 samples
ei
ret
endp
Sample: equ $
incbin "yeahh4bit_sigma_delta.bin"
LenSample equ $-Sample
end DemoPlaySample
I made some other PoC for several ways to achieve some kind of digital sound playing in a Spectrum. namely:
- Using two bits (MIC and SPK) which gives me a (very rude and non linear) 2-bit DAC
- Using the AY chip to modulate a fixed signal with the volume control
- Using PWM
- Using an actual 8-bit DAC (SpecDrum)
Results can be loaded and executed, from here:
http://www.atc.us.es/~rodriguj/prelude_spectrum.zip
The original 4 channel MOD file is included. My demos use three channels (you may not notice that until the end, in where a chord is played)
The high pitch you hear in the PWM version is caused by the PWM frequency to be so low that it enters the audible spectrum. "Serious" PWM applications use a very high pitch PWM signal.