Skip to content

AlbertVeli/ZX_Beep

Repository files navigation

 ______     __  __        ______     ______     ______     ______
/\___  \   /\_\_\_\      /\  == \   /\  ___\   /\  ___\   /\  == \
\/_/  /__  \/_/\_\/_     \ \  __<   \ \  __\   \ \  __\   \ \  _-/
  /\_____\   /\_\/\_\     \ \_____\  \ \_____\  \ \_____\  \ \_\
  \/_____/   \/_/\/_/      \/_____/   \/_____/   \/_____/   \/_/


"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).

About

Beep the ZX Spectrum

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published