Make your own free website on Tripod.com

headerdef.jpg

H O M E - APOLLO181 INTRODUCTION
Binary Clock Algorithm
Shift-and-Add Multiplication
Prime Numbers Benchmark
PWM LED Dimmer
Step Motor Controller
Sound Generator: Part 1
Sound Generator: Part 2
Random Number Generator
 
How to play sound with APOLLO181 (Part 2): the software

(Return to Part 1)

 

After having built a basic 4-bit Digital to Audio converter, in this section we compute algorithms that generate audible notes in the range of 350-3500 Hz, starting from sampled waveforms, digitized at 8000 samples per second and using 4 bits per sample, that is equal to generate a constant bit rate signal of 32 Kbit/s.

 

The first, simplest waveform is a ~1KHz pure unsigned sine wave, which I have plotted in MS Excel with -45 degrees phase shift, and digitized with 8 samples (that means 8kHz of sample rate), using 16 rounded integer levels (that means 4-bit accuracy). The following table returns the eight level values which I have calculated for each sample:

 

Sample number

Degrees

D/A

D/A binary

1

0

13

1101

2

45

15

1111

3

90

13

1101

4

135

8

1000

5

180

2

0010

6

225

0

0000

7

270

2

0010

8

315

8

1000

 

Graphs plotted in MS Excel
graph.jpg
A sine wave, with -45 phase shift, digitized at 8x sample rate, with 4-bit level accuracy

The first algorithm in APOLLO181 is very simple: just output to "port 0" the eight 4-bit binary samples, one by one, as an infinite cycle. In order to get a ~1kHz frequency, I temporarily used the trick to slow down the clock rate on the board, without computing any delay routine. The audio tone was nice to my ears and sufficiently loud.

 

1)                    Load accumulator with binary 13

2)                    Output accumulator to Port 0

3)                    Goto 4)

4)                    Load accumulator with binary 15

5)                    Output accumulator to Port 0

6)                    Goto 7)

7)                    Load accumulator with binary 13

...

...  etc etc, for binary 8, 2, 0, 2

...

22)                  Load accumulator with binary 8

23)                  Output accumulator to Port 0

24)                  Goto 1) 

Captured by a FTT spectral analysis system
1khz.jpg
A 4-bit ~1000 Hz sine wave, sampled at 8x rate, as it is reconstructed by Apollo181 DAC

 

How to invoke subprograms without Call/Return statements

 

 

As usual with APOLLO181, it is a bit of a challenge to write effective software in only 256 available memory locations . The major limitation is the no provision at all of calling subroutine instructions. Since the delay between samples must be identical, it would be a waste of memory writing the same delay routine many times, across the whole program.

 

Since in the next exercise we are going to produce a cycle of 32 different samples to reconstruct a complex periodic waveform, by using 256 Bytes of RAM we would need to write 32 nearly identical subprograms, each occupying maximum eight locations of memory (256/32=8), that generate the sample and compute the delay between two adjacent samples. This is not only impractical, but also impossible to perform.

 

The solution (source: Choosing and using 4 bit microcontrollers, by Philip McDowell, 1993, pg. 116) is making use of a table of jumps, where the return statement would be. The 'calling' section of code loads a progressive number into a dedicated register prior to jump to the 'subroutine', and at the end of the routine, this number is used as an index to a table of jumps. This means that every use of the routine must have an entry in the table, and this restricts the number of 'calls' to a maximum of sixteen for a 4-bit processor; in our case the maximum number of 'calls' is only eight, because APOLLO181's jump statement requires two instructions to be performed: the first to load the accumulator with the low-order nibble of the RAM location, and the second for the jump instruction itself, which contains the high-order nibble.

Thus, in our exercise, we will need to repeat the pseudo-call routines four times inside the main algorithm (32/8=4), that is wasteful, but anyway more efficient than writing thirty-two identical delay routines.

 

Here below you may find the structure of the algorithm for calling a subprogram many times, , by using a table of jumps without the use of Call/Return statements:

 

0)                                Return_index = 0

           

1)                                Load accumulator with sample n.1

2)                                Output accumulator to Port 0

3)                                Goto Delay_subroutine

           

4)                                Load accumulator with sample n.2

5)                                Output accumulator to Port 0

6)                                Goto Delay_subroutine

           

7)                                Load accumulator with sample n.3

8)                               

                              

 

Delay_subroutine:        CalculateDelay

                                   Increment Return_index

                                   Goto Return_index

           

Return_index 1):          Goto 4)

Return_index 2):          Goto 7)

Return_index 3):          Goto ...

…                               … 

 

 

Sound recontruction by additive synthesis

 

Joseph Fourier, mathematician and physicist of the 18th century, realized that any signal, no matter what looks the shape of the waveform, can be expressed as the sum of sinusoidal waves at various amplitudes and frequencies.

Thus, theoretically, it is possible to synthesize and reproduce any complex sound from the combination of pure sinusoidal tones. This is the concept behind additive synthesis, which involves constructing a wide range of sounds by adding up multiple sine waves at different frequencies and amplitude.

Unfortunately, a person’s voice or natural sounds are so complicated that require a nearly infinite amount of data processing to be recreated accurately. In practice, of course, the sum of sinusoidal waves is truncated to a finite number of terms, in order to considerably reduce the computational load.

ceg.jpg
C Major chord made up of three notes sounding simultaneously, transponed from C4 to C6 (at ~1kHz)

 

In this exercise we will compute an algorithm to play a major triad, that is a chord composed of three notes alone, played simultaneously.

In particular, we are going to synthesize a C Major chord, that is one of the most common chord, used in many songs. This chord is basic because it comprises only three notes: C, E, and G. These, physically, have frequencies in the ratio of 4:5:6 and when they are played together, the three notes blend very well and are pleasant to the human ear.

 

To simplify all calculations, from now on we will adopt the scientific scale, based on 'Middle C' having a frequency of 256 Hz. This is also known as the diatonic scale, that is an eight-note musical scale composed of seven pitches and a repeated octave.

 

The frequencies of the three notes in the C Major chord (starting at 'Middle C') are: C4= 256 Hz, E4= 320 Hz and G4= 384 Hz.

 

The ratio of E to C is 5/4 (or 1,25). The ratio of G to C is 6/4= 3/2 (or 1,5) and the ratio of G to E is  6/5 (or 1,2). Since the ratio between every note can be expressed as the ratio of two small whole numbers, and the frequencies of the notes are equally distant from each other, they all sound pleasant together; hence the entire major triad is consonant.

 

The resulting waveform of  C+E+G, sum of sinusoids, is like:

 

C + E + G = sin(x) + sin(5/4 x) + sin(3/2 x)

 

where:

 

C4 = sin (2πf t)

E4 = sin (5/4 * 2πf t)

G4 = sin (3/2 * 2πf t)

 

and f = 256 Hz.

 

Since the period of  C is 2π, the period of E is 4/3π and the period of G is 8/5π, the resulting period of the sum C+E+G is 8π (that is the lowest common multiple of 2π, 4/3π and 8/5π). This means that the period of the C Major chord is 4 times (8π / 2π = 4) the period of the lowest note in the chord (i.e. four times the period of C4 note).

 

Since frequency is equal to the reciprocal of the period, the fundamental frequency for the C Major chord is one fourth the frequency of the lowest note in the chord, that's one fourth of C4: thus, in the C Major chord the fundamental frequency is missing from the tone and there is no spectral energy at that frequency.

 

The fundamental missing frequency for the C Major chord results to be 256/4= 64 Hz: of course if we need to digitize such a chord with 8kHz sample rate, we would need 8000/64= 125 different samples to reconstruct it.

 

Since we have only 256 bytes of RAM available for the program, we have to transpose the C Major chord two octaves up: by transposing sound two octaves up (that means four times the frequency) we need only one fourth of the number of samples while maintaining constant the sampling rate.

 

The frequencies of the three notes in the transposed C Major chord (starting now at 'Top C') are: C6= 1024 Hz, E6= 1280 Hz and G6= 1536 Hz, and the resulting chord has a missing fundamental frequency of 1024/4= 256 Hz.

 

Since in the C Major chord, the fundamental frequency has no spectral energy, the chord can be anyway reproduced by APOLLO181, even if the small speaker cannot reproduce sounds lower than 350 Hz.

 

In order to digitize such a chord using a sampling rate of 8000 Hz, we need now to generate only 8000/256 ~ 32 different samples useful to reconstruct the whole tone.

Graphs plotted in MS Excel
sum.jpg
C Major Chord is synthetized by adding together bit-by-bit the samples of the 3 notes

Due to the lack of hardware resources, all the cumbersome calculations and the digital additive synthesis were made outside APOLLO181, under MS Excel. The algorithm is limited only to read the samples already stored in the program memory and issue them cyclically to the DAC, with the proper delay.

 

In particular I plotted for several periods each of the three sinusoids in MS Excel with +30 degrees phase shift, and I digitized, with an Excel formula, each period of the slowest wave (~1KHz sine wave) into eight samples (that means 8kHz of sample rate), by using sixteen rounded integer levels (that means 4-bit accuracy). I digitized the other two waves with the same sample rate, so, at the end, all the samples of the three waves last the same time and result synchronous. I then added together bit-by-bit the level of the corresponding samples, till covering a full period of the waveform. In fact, we have seen that the resulting wave is still periodic, with period equal to four periods of the slowest wave. For each sample I then divided the result of the sum by 3 and then I rounded it to an integer, in order to normalize the level to a 4-bit precision (that means that the peak amplitude of the level of any sample, so of the entire resulting waveform, cannot exceed binary 15).

 

The following table shows all the 32 samples (=8 samples*4 periods) which I have calculated:

 

 

Sample number

Degrees

D/A

D/A binary

 

Sample number

Degrees

D/A

D/A binary

1

0

11

1011

 

17

720

9

1001

2

45

15

1111

 

18

765

10

1010

3

90

12

1100

 

19

810

9

1001

4

135

5

0101

 

20

855

7

0111

5

180

2

0010

 

21

900

6

0110

6

225

4

0100

 

22

945

7

0111

7

270

8

1000

 

23

990

7

0111

8

315

11

1011

 

24

1035

6

0110

9

360

10

1010

 

25

1080

5

0101

10

405

8

1000

 

26

1125

7

0111

11

450

7

0111

 

27

1170

11

1011

12

495

8

1000

 

28

1215

12

1100

13

540

8

1000

 

29

1260

9

1001

14

585

6

0110

 

30

1305

3

0011

15

630

5

0101

 

31

1350

0

0000

16

675

6

0110

 

32

1395

4

0100

 

Graphs plotted in MS Excel
cmajorchordspectra.jpg
The resulting C6+E6+G6 Chord is still a periodic wave, that can be digitized with 32 samples

Captured by a FTT spectral analysis system
chordfft.jpg
C6+E6+G6 Chord, sampled at 8x rate, 4-bit accuracy, as it is reconstructed by Apollo181 DAC

 

Here you can listen to APOLLO181 C Major chord outcome and below the page you may check the full program.

PLAY APOLLO181 reconstructed chord

 

Sound reconstruction: a pencil-paper method

 

The last exercise is easy and practical. The waveform of a single tone of a real violin was recorded and printed on a paper. After that, with the use of a special grid 32x16, it was sampled with a red pencil. The 32 samples, having each 4-bit accuracy, were loaded into APOLLO181 RAM and played by using the same algorithm as was used before.

Here you can listen to the true tone of the original violin first and, after a brief pause, to APOLLO181 playing the same but reconstructed tone.

PLAY VIOLIN tone comparison

A part the natural vibrato timbre, characteristic envelope modulation of the real violin’s waveform, the two tones sound very similar to the human ear.

violinsampled.jpg
A real violin was recorded and digitized by hand using 32 samples with 4-bit precision

Captured by a FTT spectral analysis system
violinfft.jpg
The violin waveform, sampled at 8x rate, as it is reconstructed by Apollo181 DAC

 
 
 

Address          Description                APOLLO181 Code

00

49

SET ALU to 9#

01

1E

ACC = E#

02

20

REG [0] = ACC

03

21

REG [1] = ACC

04

22

REG [2] = ACC

05

23

REG [3] = ACC

06

Output sample 1

1B

ACC = B#

07

F0

OUT PORT [0] = ACC

08

16

ACC = 6#

09

08

GOTO 86#

0A

Output sample 2

1F

ACC = F#

0B

F0

OUT PORT [0] = ACC

0C

16

ACC = 6#

0D

08

GOTO 86#

0E

Output sample 3

1C

ACC = C#

0F

F0

OUT PORT [0] = ACC

10

16

ACC = 6#

11

08

GOTO 86#

12

Output sample 4

15

ACC = 5#

13

F0

OUT PORT [0] = ACC

14

16

ACC = 6#

15

08

GOTO 86#

16

Output sample 5

12

ACC = 2#

17

F0

OUT PORT [0] = ACC

18

16

ACC = 6#

19

08

GOTO 86#

1A

Output sample 6

14

ACC = 4#

1B

F0

OUT PORT [0] = ACC

1C

16

ACC = 6#

1D

08

GOTO 86#

1E

Output sample 7

18

ACC = 8#

1F

F0

OUT PORT [0] = ACC

20

16

ACC = 6#

21

08

GOTO 86#

22

Output sample 8

1B

ACC = B#

23

F0

OUT PORT [0] = ACC

24

16

ACC = 6#

25

08

GOTO 86#

26

Output sample 9

1A

ACC = A#

27

F0

OUT PORT [0] = ACC

28

14

ACC = 4#

29

09

GOTO 94#

2A

Output sample 10

18

ACC = 8#

2B

F0

OUT PORT [0] = ACC

2C

14

ACC = 4#

2D

09

GOTO 94#

2E

Output sample 11

17

ACC = 7#

2F

F0

OUT PORT [0] = ACC

30

14

ACC = 4#

31

09

GOTO 94#

32

Output sample 12

18

ACC = 8#

33

F0

OUT PORT [0] = ACC

34

14

ACC = 4#

35

09

GOTO 94#

36

Output sample 13

18

ACC = 8#

37

F0

OUT PORT [0] = ACC

38

14

ACC = 4#

39

09

GOTO 94#

3A

Output sample 14

16

ACC = 6#

3B

F0

OUT PORT [0] = ACC

3C

14

ACC = 4#

3D

09

GOTO 94#

3E

Output sample 15

15

ACC = 5#

3F

F0

OUT PORT [0] = ACC

40

14

ACC = 4#

41

09

GOTO 94#

42

Output sample 16

16

ACC = 6#

43

F0

OUT PORT [0] = ACC

44

14

ACC = 4#

45

09

GOTO 94#

46

Output sample 17

19

ACC = 9#

47

F0

OUT PORT [0] = ACC

48

12

ACC = 2#

49

0A

GOTO A2#

4A

Output sample 18

1A

ACC = A#

4B

F0

OUT PORT [0] = ACC

4C

12

ACC = 2#

4D

0A

GOTO A2#

4E

Output sample 19

19

ACC = 9#

4F

F0

OUT PORT [0] = ACC

50

12

ACC = 2#

51

0A

GOTO A2#

52

Output sample 20

17

ACC = 7#

53

F0

OUT PORT [0] = ACC

54

12

ACC = 2#

55

0A

GOTO A2#

56

Output sample 21

16

ACC = 6#

57

F0

OUT PORT [0] = ACC

58

12

ACC = 2#

59

0A

GOTO A2#

5A

Output sample 22

17

ACC = 7#

5B

F0

OUT PORT [0] = ACC

5C

12

ACC = 2#

5D

0A

GOTO A2#

5E

Output sample 23

17

ACC = 7#

5F

F0

OUT PORT [0] = ACC

60

12

ACC = 2#

61

0A

GOTO A2#

62

Output sample 24

16

ACC = 6#

63

F0

OUT PORT [0] = ACC

64

12

ACC = 2#

65

0A

GOTO A2#

66

Output sample 25

15

ACC = 5#

67

F0

OUT PORT [0] = ACC

68

10

ACC = 0#

69

0B

GOTO B0#

6A

Output sample 26

17

ACC = 7#

6B

F0

OUT PORT [0] = ACC

6C

10

ACC = 0#

6D

0B

GOTO B0#

6E

Output sample 27

1B

ACC = B#

6F

F0

OUT PORT [0] = ACC

70

10

ACC = 0#

71

0B

GOTO B0#

72

Output sample 28

1C

ACC = C#

73

F0

OUT PORT [0] = ACC

74

10

ACC = 0#

75

0B

GOTO B0#

76

Output sample 29

19

ACC = 9#

77

F0

OUT PORT [0] = ACC

78

10

ACC = 0#

79

0B

GOTO B0#

7A

Output sample 30

13

ACC = 3#

7B

F0

OUT PORT [0] = ACC

7C

10

ACC = 0#

7D

0B

GOTO B0#

7E

Output sample 31

10

ACC = 0#

7F

F0

OUT PORT [0] = ACC

80

10

ACC = 0#

81

0B

GOTO B0#

82

Output sample 32

14

ACC = 4#

83

F0

OUT PORT [0] = ACC

84

10

ACC = 0#

85

0B

GOTO B0#

86

1st Delay routine

90

SET NO CARRY

87

30

ACC = REG [0]

88

52

ACC = Arithm f (ACC, 2#, CARRY)

89

20

REG [0] = ACC

8A

90

SET NO CARRY

8B

E7

ACC = IN PORT [7]

8C

2F

REG [F] = ACC

8D

3F

ACC = REG [F]

8E

51

ACC = Arithm f (ACC, 1#, CARRY)

8F

2F

REG [F] = ACC

90

30

ACC = REG [0]

91

DC

IF CARRY GOTO Cx#

92

1D

ACC = D#

93

08

GOTO 8D#

94

2nd Delay routine

90

SET NO CARRY

95

31

ACC = REG [1]

96

52

ACC = Arithm f (ACC, 2#, CARRY)

97

21

REG [1] = ACC

98

90

SET NO CARRY

99

E7

ACC = IN PORT [7]

9A

2F

REG [F] = ACC

9B

3F

ACC = REG [F]

9C

51

ACC = Arithm f (ACC, 1#, CARRY)

9D

2F

REG [F] = ACC

9E

31

ACC = REG [1]

9F

DD

IF CARRY GOTO Dx#

A0

1B

ACC = B#

A1

09

GOTO 9B#

A2

3rd Delay routine

90

SET NO CARRY

A3

32

ACC = REG [2]

A4

52

ACC = Arithm f (ACC, 2#, CARRY)

A5

22

REG [2] = ACC

A6

90

SET NO CARRY

A7

E7

ACC = IN PORT [7]

A8

2F

REG [F] = ACC

A9

3F

ACC = REG [F]

AA

51

ACC = Arithm f (ACC, 1#, CARRY)

AB

2F

REG [F] = ACC

AC

32

ACC = REG [2]

AD

DE

IF CARRY GOTO Ex#

AE

19

ACC = 9#

AF

0A

GOTO A9#

B0

4th Delay routine

90

SET NO CARRY

B1

33

ACC = REG [3]

B2

52

ACC = Arithm f (ACC, 2#, CARRY)

B3

23

REG [3] = ACC

B4

90

SET NO CARRY

B5

E7

ACC = IN PORT [7]

B6

2F

REG [F] = ACC

B7

3F

ACC = REG [F]

B8

51

ACC = Arithm f (ACC, 1#, CARRY)

B9

2F

REG [F] = ACC

BA

33

ACC = REG [3]

BB

DF

IF CARRY GOTO Fx#

BC

17

ACC = 7#

BD

0B

GOTO B7#

BE

NOP

10

ACC = 0#

BF

NOP

10

ACC = 0#

C0

1st Jump Table

1A

ACC = A#

C1

00

GOTO 0A#

C2

1E

ACC = E#

C3

00

GOTO 0E#

C4

12

ACC = 2#

C5

01

GOTO 12#

C6

16

ACC = 6#

C7

01

GOTO 16#

C8

1A

ACC = A#

C9

01

GOTO 1A#

CA

1E

ACC = E#

CB

01

GOTO 1E#

CC

12

ACC = 2#

CD

02

GOTO 22#

CE

16

ACC = 6#

CF

02

GOTO 26#

D0

2nd Jump Table

1A

ACC = A#

D1

02

GOTO 2A#

D2

1E

ACC = E#

D3

02

GOTO 2E#

D4

12

ACC = 2#

D5

03

GOTO 32#

D6

16

ACC = 6#

D7

03

GOTO 36#

D8

1A

ACC = A#

D9

03

GOTO 3A#

DA

1E

ACC = E#

DB

03

GOTO 3E#

DC

12

ACC = 2#

DD

04

GOTO 42#

DE

16

ACC = 6#

DF

04

GOTO 46#

E0

3rd Jump Table

1A

ACC = A#

E1

04

GOTO 4A#

E2

1E

ACC = E#

E3

04

GOTO 4E#

E4

12

ACC = 2#

E5

05

GOTO 52#

E6

16

ACC = 6#

E7

05

GOTO 56#

E8

1A

ACC = A#

E9

05

GOTO 5A#

EA

1E

ACC = E#

EB

05

GOTO 5E#

EC

12

ACC = 2#

ED

06

GOTO 62#

EE

16

ACC = 6#

EF

06

GOTO 66#

F0

4th Jump Table

1A

ACC = A#

F1

06

GOTO 6A#

F2

1E

ACC = E#

F3

06

GOTO 6E#

F4

12

ACC = 2#

F5

07

GOTO 72#

F6

16

ACC = 6#

F7

07

GOTO 76#

F8

1A

ACC = A#

F9

07

GOTO 7A#

FA

1E

ACC = E#

FB

07

GOTO 7E#

FC

12

ACC = 2#

FD

08

GOTO 82#

FE

16

ACC = 6#

FF

00

GOTO 06#

 

DISCLAIMER & CREDIT: All data here reproduced are for educational and non-commercial purpose, following fair-use guidelines.

This is an INDIPENDENT AND UNOFFICIAL hobby site. Either Dr. Peter R. Rony or the Blacksburg group or Computer History Museum (Mountain View, CA) or other third-party DO NOT HAVE ANY ASSOTIATION with this work.

Author G.G. DOESN'T EARN ANYTHING FROM ADVERTISEMENT. This site is not in the business of making money. This site is visible thanks to the Free Web Hosting Tripod Service, so it is ad-supported: advertisement contents, costs and revenues are full managed by the service itself. Author does not have any involvement in them. The advertising links in the Site pages and in the pop-up windows are not Author's property. They can change and the Author is non-responsible about their contents and working. The Author is not responsible about the linked sites.
The information presented here is just that: INFORMATION. Use it at your own risk and for only non commercial purpose. The information here presented is believed to be technically correct and everything presented on this site is done so in good faith. Anyhow you (the reader) are responsible for anything that you might do as a result of reading this article. You assume complete and total responsibility for your actions! Author is not responsible for any misuse or damage coming from the reading and using this information.

Text and images from original typewritten Bugbooks I and II in 1974 are permission courtesy of Dr. Peter R. Rony, the original author and sole copyright owner of the Bugbooks I, II, IIA, III, V, and VI.

The background image on the header of each page of the site is "Sunset over western South America" photographed on 12 April 2011 by an Expedition 27 crew member on the International Space Station. (Image credit: NASA). On it I have merged titles and a my photo of TIL302 displays.

Texas Instruments data are Texas Instruments Copyright and reported by Courtesy of Texas Instruments.

 

TERM OF USE: With clear exception for texts and images which are not author's property, Gianluca G. freely authorizes you the downloading, printing and reproducing of APOLLO181 data, texts and images ONLY for non-commercial usage and ONLY if you give a clear reference to its source and project namewithout any right to resell or redistribute them or to compile or create derivative works.

Any rights not expressly granted herein are reserved.

 

Copyright (c) 2012 by Gianluca G. Italy