-
Notifications
You must be signed in to change notification settings - Fork 0
/
README
230 lines (157 loc) · 7.76 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
______ __ __ ______ ______ ______ ______
/\___ \ /\_\_\_\ /\ == \ /\ ___\ /\ ___\ /\ == \
\/_/ /__ \/_/\_\/_ \ \ __< \ \ __\ \ \ __\ \ \ _-/
/\_____\ /\_\/\_\ \ \_____\ \ \_____\ \ \_____\ \ \_\
\/_____/ \/_/\/_/ \/_____/ \/_____/ \/_____/ \/_/
"What is a Computer Good For? Your new Timex Sinclair 2000 computer is
a very special instrument. It is a tool that can increase the power of
your mind as a hammer or a wheelbarrow assists your muscles."
--TS2068 User Manual
The purpose of this repository is primarily to be a skeleton you can
base your own ZX Spectrum projects upon. It compiles assembly code and
outputs a TAP-file, which can be read by most Spectrum emulators. I
use fuse. http://fuse-emulator.sourceforge.net/
BACKGROUND
When I was young the ZX Spectrum was a great inspiration. Me and my
friends entered BASIC-programs from computer magazines and manuals on
those soft rubber-keys. Even though we didn't realize it at the time,
we had embarked upon a path of learning the art (or should I call it
science?) of computer software programming. Today we can emulate that
childhood with tools like fuse, and even write new code for it.
BUT WHAT DOES IT DO?
ZX Beep repeatedly calls the BEEPER subroutine in the Spectrum ROM to
play some sweeping sound effects and an example song called Mandom
Mod. A marching tune written a long time ago in a place far, far away
(Orsa/Dalarna), long before the age of impeding copyright claims.
http://albertveli.github.io/ZX_Beep/img/mandom_mod.png
BUILD
You need a git client, make and a C-compiler. On Debian-based systems
these can be found in the packages git, make and gcc:
apt-get install git make gcc
See http://help.github.com/articles/set-up-git for info on installing
git on various systems.
I have successfully compiled the code on Gentoo, Debian and OS X
Mountain Lion. OS X had make and gcc installed by default, so I only
had to install git. On Windows it is possible to compile it using
Msys+MinGW+Git, see mingw_install.rtf.
Ok, lets go. Fetch the ZX Beep source code from github:
git clone https://github.com/AlbertVeli/ZX_Beep.git
And build it with make:
make
If everything works out, beep.tap should be created.
MODIFY
To create your own TAP-file, edit the first lines in the Makefile (SRC
and INCSRCS), and replace with your own .asm file(s).
If you want to use it as-is and only create a new song, copy
mandom_mod.asm to a new file with the name of your song and change the
notes data. Then replace the string "mandom_mod.asm" in Makefile /
beep.asm. If you change some of the mandom_mod labels in the song
file, remember to do the corresponding changes in beep.asm.
You may also want to remove the line 'include "sweep.asm"' and the
calls to sweep_octave from beep.asm to save some precious space. To
save even more space it is possible to remove entire octaves from
octaves.asm (but only at the beginning and at the end). You can for
instance remove the A1, A6 and A7 octaves if they are not used.
SONG DATA
Structure: Each note consist of a Pitch,Length pair in the range
0-255 (one byte).
Pitch = number of semitones above the first note. If A2 (A number
2 on piano) is the base octave, the pitch values becomes:
0 A2, 1 Bb, 2 B, 3 C, 4 C#, 5 D, 6 Eb, 7 E, 8 F, 9 F#, 10 G, 11 G#
12 A3, 13 Bb, 14 B, 15 C, 16 C#, 17 D, 18 Eb, 19 E, 20 F, 21 F#, 22 G, 23 G#
24 A4, 25 Bb, 26 B, 27 C, 28 C#, 29 D, 30 Eb, 31 E, 32 F, 33 F#, 34 G, 35 G#
etc
Length = Duration of note:
1 -> Whole note (1 s)
2 -> Half note (1/2 s)
3 -> Quarter note (1/4 s)
4 -> Eigth note (1/8 s)
5 -> Sixteenth note (1/16 s)
6 -> Thirty-second note (1/32 s)
etc
Example. 19,4 -> E3, Eigth note.
FREQUENCIES
In the song data frequencies are given as semitones above the base
note. But the BEEPER subroutine in ROM neither takes frequencies in
Hz, nor in semitones. Instead the frequency data word is calculated in
a rather intricate manner. See comments just before L03B5 in the ROM
disassembly:
http://www.wearmouth.demon.co.uk/zx82.htm#L03B5
The algorithm given in the disassembly translates from frequency (Hz)
to register values. But we also need to calculate what frequency to
use somehow.
It turns out there are many ways to calculate tone frequencies. The
standard way is to use 440 Hz for the fourth A on a piano (A4) and
calculate the rest of the frequencies relative 440 Hz with the
alorithm EQUAL TEMPERAMENT. With this algorithm the frequency for a
note n semitones away from A4 becomes:
Freq(n) = 440 * 2^(n/12)
This works for all keys (because the errors are evenly distributed).
But if you want to fine tune harmonies for a specific key, Hermann von
Helmholtz (in the book "Sensations of Tone", published 1863) figured
out more optimal frequencies. The following ratios (relative the base
note frequency) can be used to calculate the 12 notes in an octave:
1 / 1 ; 0 Unison
25 / 24 ; 1 Minor Second
9 / 8 ; 2 Major Second
6 / 5 ; 3 Minor Third
5 / 4 ; 4 Major Third
4 / 3 ; 5 Fourth
45 / 32 ; 6 Diminished Fifth
3 / 2 ; 7 Fifth
8 / 5 ; 8 Minor Sixth
5 / 3 ; 9 Major Sixth
9 / 5 ; 10 Minor Seventh
15 / 8 ; 11 Major Seventh
This is called the JUST scale (aka Harmonic or Helmholtz). Helmholtz
based his work on older philosophical writings attributed to people
like Pythagoras, Andreas Werckmeister et al. The essence is: lower
numbers in the ratio -> better harmony.
Example. A4 = 440 Hz, C (minor third relative A, 3 semitones up)
becomes:
JUST ; 440 * (6/5) = 528 Hz
EQ.TEMPERED ; 440 * 2^(3/12) = 523.25 Hz
The difference can easily be heard by the naked ear. Try playing two
tones, 440 and 528 Hz together. Then compare to 440 / 523.25 Hz. The
first tone-pair gives cleaner harmony (it is also possible to
visualize this difference using Lissajous curves).
The downside of JUST scale is that frequencies has to be re-calculated
to play a song in a different key. EQUAL TEMPERAMENT is a compromise
tuning that works equally well (or bad) for all keys.
These frequency calculations are performed by freqs.c and output to
octaves.asm. The pre-calculated lookup-tables in octaves.asm are then
used by the beeper routine in beep.asm. To change scale, compile
freqs.c by running "make freqs" and generate the frequencies of your
choice.
Example. Seven octaves in JUST scale, starting at C = 256 Hz (makes
all C:s powers of two and the other notes low-integer ratios in
relation to powers of two) run:
./freqs -o 7 -j 256
And to generate six octaves with the vanilla EQUAL TEMPERED scale,
starting at 110 Hz (A, two octaves below 440 Hz), run:
./freqs -o 6 110
Paste the output into octaves.asm and build a new TAP.
EXTERNAL CODE USED
- z80asm ; http://www.nongnu.org/z80asm/
Z80asm is included as a git submodule. The submodule will be fetched
the first time you run make.
REFERENCES
- The BASIC manual for ZX Spectrum is exceptionally well
written. Start there.
http://www.worldofspectrum.org/ZXBasicManual/index.html
- World of Spectrum has links tho all things Spectrum
http://www.worldofspectrum.org/
- Introduction to Z80 Assembler
http://www.worldofspectrum.org/Z80.html
- Z80 Heaven has details for the complete Z80 instruction set
http://z80-heaven.wikidot.com/instructions-set
- Details of what happens in each Z80 instruction Machine Cycle*
http://www.z80.info/z80ins.txt
Happy Hacking!
/Albert
* Each Machine Cycle takes 3-6 T-cycles (real CPU clock
cycles). Spectrum runs the Z80 at 3.5 MHz. Example. If an
instruction takes 9 T-cycles it will execute in 9/3500000 seconds =
2.57 microseconds. Z80 was pretty deterministic. Modern CPU:s are
more unreliable when it comes to timing (caches, pipelining etc
complicate matters).