file_id.diz
***********************************************************************************************
ANTEATER music routine for ZX Spectrum
by utz 08'2014
***********************************************************************************************
1 square wave channel, 1 pwm channel, drums
Requirements:
=============
In order to use anteater, you will need
- pasmo or another Z80 assembler of your choice
- Perl for compiling the music from an XM file
- Milkytracker or another XM tracker for writing music
Writing Music
=============
You can compose music using the included music.xm template. It gives only a rough impression of
how the music will sound on actual hardware though.
You can set the song speed with the global "Spd" setting, or at any given point with command
Fxx. Valid values are 1..$1f (31). BPM settings are ignored.
Notes go in tracks 1 and 2. Track 1 is the square wave channel, track 2 is the PWM channel.
You can use notes from C-1 to B-7. However, notes in higher octaves are prone to detuning,
which is not reflected in the xm template.
You can use manual detune on both tone channels with command E5x.
You can put drums in any channel, their pitch will be ignored.
All other effect commands are ignored.
Compiling
=========
Provided you have Perl and pasmo installed on your system, simply run the
compile.bat resp. compile.sh scripts.
anteater Music Data Format
==========================
You can also code the music.asm file by hand, if you like. The music data consists of an
order list containing the sequence of patterns, followed by the pattern data itself.
The order list must be ended with dw #0000, patterns must end with db #ff.
byte 1 = speed+drum or pattern end marker (#ff)
drum can be 0 (no drum), 1 (kick), 2 (snare) or 3 (hihat)
speed can be #04..#fc, must be a multiple of 4
bytes 2-3 = tone counters ch1-ch2
values are inverse, ie. higher value means lower tone
Trivia
======
The name "anteater" is a reference to the game "Ant Attack" by Sandy White and Angela Sutherland,
which is probably the first game on the Speccy to use pulse interleaving beeper sound.
********************************************************************************
BEEPERTOY v0.1
by utz 06'2016 * www.irrlichtproject.de
********************************************************************************
================================================================================
About
================================================================================
BEEPERTOY is a multi-paradigm sound routine for the ZX Spectrum beeper. It
generates sound through a number of different methods, including pulse frequency
modulation, pulse interleaving, and wavetable synthesis. It also features some
advanced effects such as low- and high-pass filters, and a simple reverb.
Beepertoy is made up of a number of different "cores", each providing a
different configuration. The user can switch between cores at any time between
two notes.
The available configurations as of version 0.1 are:
1) SQUEEKER EMULATOR: 4 channels of short pulse with configurable width
2) 4x PIN: 4 channels of pin pulse
3) TRITONE EMULATOR: 3 channels of square wave with configurable duty, with
various noise/glitch modes
4) OCTODE EMULATOR: 8 channels of pin pulse
5) 3x WAVETABLE + FILTERS: 3 channels of wavetable synthesis (256B tables),
optional global lo/hi-pass
6) 2x SQUARE + FILTERS + VOLUME + FX: 2 channels of square wave with
configurable duty cycle, volume control, reverb or fixed-pitch sample,
optional global lo-pass, one of the channels can play noise
7) ROM NOISE: simple noise generator
All configurations provide additional support for configurable click drums.
================================================================================
NMOS vs CMOS Z80
================================================================================
Beepertoy uses the OUT (C),0 command, which has different effects on NMOS
(original Spectrum) and CMOS (many Spectrum clones) CPUs. The driver will
attempt to detect the CPU type on startup and patch the code accordingly.
However, this is somewhat unreliable and may fail on some machines. You can
disable CPU detection and force compilation to either NMOS or CMOS by modifying
line 34 in main.asm. To force the NMOS version, simply comment out the line.
To force the CMOS version, replace the CALL to "detectCPU" with a CALL to
"patchCMOS".
Credit for the MOS detection code goes to introspec and JtN.
================================================================================
Usage
================================================================================
Unfortunately Beepertoy is too complex to simulate via an XM template, so
currently music can only be made by coding in assembly.
SEQUENCE
Music data for Beepertoy must always start with a song sequence, ie. a list of
patterns in the desired play order. The sequence list is terminated with a
0-word. The sequence must also contain the label "loop" at some point - this
specifies the position the player will loop to once it has reached the end of
the sequence. To disable looping, uncomment line 60 in main.asm.
WAVETABLES/SAMPLES
Samples in Beepertoy are simple 256-byte PCM wavetables. Normally, each
wavetable should contain a single waveform. When using more complex waveforms
(for example percussion), trigger them at a low frequency.
Each byte in a wavetable represents a relative sample volume at a given time.
The maximum combined relative volume of all samples used at a given pattern row
must not exceed 12. Usually this means that all values in your sample should be
between 0 and 4.
All samples must be included in the samples.asm file. You can provide an empty
samples.asm file if you don't want to use samples, however you can not omit it
unless you modify main.asm accordingly.
PATTERN DATA
The layout of the pattern data varies depending on which synthesis configuration
is used. However, there are a few common traits.
Most importantly, all patterns must terminate with a single byte with the value
0x40.
All pattern rows start with a word containing the speed (length of the row in
ticks, that is) in the high byte, and drum flags in the low byte. The speed
value should not exceed 0x3f. The drum flags are as follows:
bit 0: hi-hat
bit 2: kick
bit 7: snare
Only one of the flags may be set in any given row.
If a drum is used, the second entry of the pattern row is a word specifying the
volume of the drum. The low byte is the actual volume (0x80 is the maximum,
volume decreases with both lower and higher values). The high byte is always 0.
If the current row does not use click drums, this word is omitted.
After this, everything depends on the synth configuration you intend to use. A
description of the various configurations follows.
================================================================================
SQUEEKER EMULATOR
================================================================================
As the name suggests, this configuration uses the synthesis method from
Zilogat0r's Squeeker engine. It supports 4 channels, but unlike with the
original Squeeker, each channel can have it's own duty cycle setting. A data
row for this configuration is constructed as follows:
dw <SPEED * 256 + FLAGS>
[dw <DRUM VOL>]
dw <DUTY.CHANNEL1 * 256 + DUTY.CH2>
dw <DUTY.CH3 * 256 + DUTY.CH4>
dw squeekpin0
dw <FREQUENCY.CH4>
dw <FREQ.CH1>
dw <FREQ.CH2>
dw <FREQ.CH3>
================================================================================
4x PIN
================================================================================
Ordinary 4-channel accumulating PFM (pin pulse) synthesis. This configuration is
really quite basic. It is considered for removal in a later version of
Beepertoy. For now, data rows are constructed as follows:
dw <SPEED * 256 + FLAGS>
[dw <DRUM VOL>]
dw 0
dw 0
dw accupin0
dw <FREQ.CH1>
dw <FREQ.CH2>
dw <FREQ.CH3>
dw <FREQ.CH4>
================================================================================
TRITONE EMULATOR
================================================================================
A somewhat loose emulation of Shiru's Tritone engine, this configuration plays 3
channels of square wave with configurable duty cycles. Some channels can be
configured to play noise or glitchy sounds instead of tone. It runs twice as
fast, and plays at double pitch compared to the other configurations. Channels 1
and 2 have the same volume, channel 3 is about 45% louder.
Data rows are constructed as follows:
dw <SPEED * 256 + FLAGS>
[dw <DRUM VOL>]
dw <DUTY.CHANNEL1 * 256 + DUTY.CH2>
dw <DUTY.CH3 * 256 + FX_CONFIG>
dw tritone0
dw <FREQ.CH2>
dw <FREQ.CH3>
dw <FREQ.CH1>
The following FX CONFIGurations are available
CONFIG effect
#07 no effect
#05 vibrato ch2 (strength varies depending on freq.ch2, often quite subtle)
#04 play noise on ch2
#02 glitch ch2
#00 glitch ch3
In order to play noise, you need to feed ch2 with a suitable frequency value.
#35d1 is usually a good bet.
================================================================================
OCTODE EMULATOR
================================================================================
This configuration emulates Shiru's Octode engine, providing 8 channels of pin
pulse sound. However, unlike the original it uses 16-bit note counters. Some
corners had to be cut in order to achieve this within the limitations of
Beepertoy. As a result, you cannot run this config with all channels muted.
Channel 8 must always have a note set, and the note value must be between #0100
and #e000. Also, the sound core runs very slightly out of sync. Speed is off by
about -0.13%, and pitch is off by about -0,52% compared to the other
configurations.
Data rows are constructed as follows:
dw <SPEED * 256 + FLAGS>
[dw <DRUM VOL>]
dw <FREQ.CH1>
dw <FREQ.CH2>
dw octode0
dw <FREQ.CH3>
dw <FREQ.CH4>
dw <FREQ.CH5>
dw <FREQ.CH6>
dw <FREQ.CH7>
dw <FREQ.CH8> (must be >= #1000 && < #e000)
================================================================================
3x WAVETABLE + FILTERS
================================================================================
This configuration allows you to play 3 channels of table-based waveforms
(samples), with optional global filters. Data rows are constructed as follows:
dw <SPEED * 256 + FLAGS>
[dw <DRUM VOL>]
dw #0
dw <FILTER_CONFIG_A>
dw <FILTER_CONFIG_B>
dw <FREQ.CH1>
dw <SAMPLE.CH1>
dw <FREQ.CH2>
dw <SAMPLE.CH2>
dw <FREQ.CH3>
dw <SAMPLE.CH3>
The following FILTER CONFIGurations are available:
CONFIG_A CONFIG_B effect
#0 core0hs hi-pass (not very effective, unfortunately)
#17cb core0S no filter
#0 core0S lo-pass, high cut-off
#2fcb core0S lo-pass, low cut-off
Note that the filters can kill the sound entirely at very low volumes.
================================================================================
2x SQUARE + FILTERS + VOLUME + FX
================================================================================
This configuration allows you to play 2 channels of square waves with
configurable duty cycle, with optional global lo-pass and reverb. Reverb is not
very effective, and may at times lead to rather unexpected results. You can also
deactivate reverb, or play a fixed-pitch sample instead. Both channels have
volume control. Channel 2 can be configured to play noise.
Data rows are constructed as follows:
dw <SPEED * 256 + FLAGS>
[dw <DRUM VOL>]
dw <REVERB_CONFIG_A>
dw <REVERB_CONFIG_B>
dw <NOISE> ("core0" to disable, "core0n" to enable)
dw <FREQ.CH1>
dw <DUTY.CH1 * 256 + VOLUME.CH1>
dw <FREQ.CH2>
dw <DUTY.CH2 * 256 + VOLUME.CH2>
dw <FILTER_CONFIG>
The combined volume of both channels must not exceed 8 when reverb or sample
playback is enabled, and must not exceed 12 when reverb/sample playback is
disabled. For sample playback, the sample may not exceed a volume of 4.
The following REVERB CONFIGurations are available:
CONFIG_A CONFIG_B effect
dw reverbBuffer dw reverbBuffer+#nn enable reverb with delay length #nn
dw reverbBufferEmpty dw reverbBuffer disable reverb
dw <SAMPLE> dw reverbBuffer enable fixed-pitch sample playback
The following FILTER CONFIGurations are available:
CONFIG effect
#17cb no filter
#0 lo-pass, high cut-off
#2fcb lo-pass, low cut-off
Note that the lo-pass can kill the sound entirely at very low volumes.
In order to play noise, you need to feed ch2 with a suitable frequency value.
#35d1 is usually a good bet.
================================================================================
ROM NOISE
================================================================================
This configuration will simply read values from the ROM (and eventually, RAM),
and send them to the beeper, producing some ear-deafening noises.
Data rows are constructed as follows:
dw <SPEED * 256 + FLAGS>
[dw <DRUM VOL>]
dw <POINTER TO ROM> (eg. dw 0)
dw 0
dw romNoise0
Parsing is fast at 1792 bytes per tick, meaning you will have played the entire
ZX Spectrum address space after about 37 ticks.
================================================================================
GREETINGS AND THANKS TO
================================================================================
Alone Coder, Factor6, garvalf, introspec, Mister Beep, Shiru, TDM, Tufty,
Zilogat0r
================================================================================
eof.********************************************************************************
BM-1, aka BeepModular-1
by utz 02'2017 * irrlichtproject.de | github.com/utz82
********************************************************************************
About
=====
BM-1 is an experimental sound routine for the ZX Spectrum beeper. It features a
highly versatile synthesis core that can be modified during runtime, which
makes it possible to generate a near-endless range of different sounds.
Features include:
- 2 tone channels, 12-bit or 15-bit frequency dividers
- patches: on-the-fly modifications of the synthesis algorithm
- volume control (8 levels per channel, availability depends on patch)
- tables: change pitch and fx parameters per tick
- functions: arbitrary code execution/modification once per tick
- customizable click drums
- per-step tempo control
- compact player size (375 bytes, can be reduced by disabling features)
- optimized data format
With patches, you can produce
- variable duty cycles
- phatness/harmonics control
- fake chords
- bytebeat-like glitches
- SIDsound (duty sweep)
- PFM (classic pin pulse sound)
- noise
Usage
=====
Unfortunately no editor exists for this engine, so any music must be composed
directly in assembly. Furthermore, at least a basic understand of Z80 machine
code is required, as BM-1 makes use of actual code snippets (called "patches")
embedded within the song data. Note that it is perfectly possible to crash the
player through use of invalid code.
The code is intended to be assembled with Pasmo.
Music Data Format
=================
Music data for BM-1 consists of a sequence, one or more patterns, one or more
patches, one or more fx tables (omitted when USETABLES is set to 0 in main.asm),
and optionally blocks of code to be executed by fx tables.
SEQUENCE:
A list of pattern pointers in the order in which they are to be played. The list
is terminated with a 0-word. Unless USELOOP is set to 0 in main asm, a label
called "mloop" must be used within the sequence to specify the position the
player will loop to after completing the sequence. A simple valid sequence thus
may look like this:
mloop
dw ptn0
dw 0
PATTERNS:
Patterns contain the actual music data. Each pattern row contains 2-11 word-
length entries. The layout is as follows:
word 0: drum_parameter << 8 | control_byte0
ctrl0 bit 7 set: trigger noise click drum
-> drum_param bit 0..6 sets volume
drum_param bit 7 toggles high/low pitch (set = hi)
ctrl0 bit 6 set: end of pattern (all patterns should terminate with
db #40).
ctrl0 bit 2 set: trigger kick click drum (ignored when bit 7 is set)
-> drum_param set starting pitch
ctrl0 bit 0 set: skip loading all channel parameters (omit words 1..8)
drum_param should be 0 if no click drums are triggered (affects lo-byte
of tempo counter)
word 1: patch_param1_7 << 8 | control_byte1
ctrl1 bit 7 set: skip patch_param1_8..11
ctrl1 bit 6 set: no patch update (omit word 2)
ctrl1 bit 2 set: skip patch_param1_1..6
ctrl1 bit 0 set: skip all updates for ch1 (omit words 2..4)
word 2: patch_pointer_ch1
word 3: frequency_divider_ch1
if bit 15 is reset, omit word 4
word 4: generic_parameter_ch1
word 5: patch_param2_7 << 8 | control_byte2
ctrl1 bit 7 set: skip patch_param2_8..11
ctrl1 bit 6 set: no patch update (omit word 6)
ctrl1 bit 2 set: skip patch_param2_1..6
ctrl1 bit 0 set: skip all updates for ch2 (omit word 6..8)
word 6: patch_pointer_ch2
word 7: frequency_divider_ch2
if bit 15 is reset, omit word 8
word 8: generic_parameter_ch2
word 9: row_tempo << 8 | control_byte3
ctrl3 bit 6 set: skip table_pointer update (omit word 10)
word 10: table_pointer
All values except the generic parameters must be initialized at the beginning of
the sequence.
Each pattern must end with and end marker (= db #40, see ctrl0), unless followed
by another pattern (which will be loaded once the current one is completed).
TABLES:
Tables contain additional data, which is parsed once per row tick (eg. at a rate
of about 61 Hz). Tables can modify the frequency dividers, and the generic
parameters. They can also modify everything else via function execution. The
layout is as follows:
word 0: control_byte0
ctrl0 bit 7 set: perform table jump (pointer to table location follows)
ctrl0 bit 6 set: stop table execution (hi-byte can be omitted)
ctrl0 bit 2 set: execute function (pointer to function follows)
ctrl0 bit 0 set: no update on this tick (hi-byte is omitted)
any of the above, omit word 1..5
word 1: control_byte1
ctrl1 bit 7 set: skip freq_div2 update (omit word 4)
ctrl1 bit 6 set: skip freq_div1 update (omit word 2)
ctrl1 bit 2 set: skip generic_param2 update (omit word 5)
ctrl1 bit 0 set: skip generic_param1 update (omit word 3)
word 2: frequency_divider_ch1
word 3: generic_parameter_ch1
word 4: frequency_divider_ch2
word 5: generic_parameter_ch2
Each tables must end with either a table jump, or a table stop (= db #40),
unless followed by another table (which will be loaded once the current one is
completed).
PATCHES:
Patches are code templates, which are copied into the synthesis core at runtime.
They consist 10 single-byte, 4-cycle instructions, or an equivalent amout of
2-byte, 8-cycle instructioins. The first 6 instructions or the last 4
instructions may be omitted, if the control bytes of pattern row that sets the
patch (ctrl1 resp. ctrl2) are set accordingly. An additional instruction is
set directly by the control byte. Instructions are executed as follows:
- Instruction 1..6 are executed before the first OUT command (patchX_1..6), ie.
before the channel starts playing. At this point the channel frequency counter
has been updated, and the high-byte of the counter has been loaded into the
accumulator A.
- The additional instruction set by the ctrl1/2 is executed between the first
and the second OUT command (patchX_7), ie. after the channel has played for
16 cycles
- Instruction 8-10 are executed between the second and the third OUT command
(patchX_8..11), ie. after the channel has played for 16+32=48 cycles. After
the third OUT command, the channel will continue to play for another 64
cycles, resulting in a total playtime of 128 cycles per sound loop iteration.
As mentioned before, only instructions that align to 4 cycles per instruction
byte can be used. It is entirely possible to break the player with patch code,
hence caution is advised. Some general rules of thumb:
- Stick to instructions that modify either the accumulator A, or the generic
parameters (IXH/IXL for ch1, IYH/IYL for ch2).
- Be extra careful when modifying registers D,E,H,L and their shadow
counterparts.
- It is almost certainly a bad idea to use indirect jumps (jp (hl/ix/iy)).
- It is almost certainly a bad idea to modify registers B, C, B', C'.
Some standard patches are provided as macros in patches.h, check them for
further reference.
FUNCTIONS:
Functions can contain arbitrary code, which may modify any sound parameter and/
or the synthesis core. Function code is triggered by table execution.
Each function must end with a jump to either noTableExec or tblStdUpdate. When
jumping to noTableExec, the player will return to the synthesis core. When
jumping to tblStdUpdate, the player will immediately parse another row of table
data instead.
Using functions poses a significant risk of breaking/crashing the engine, of
course. Do not use this feature unless you have a good understanding of how the
engine code works.
Generally speaking, any operations involving the stack is almost guaranteed to
crash the player.
Assembler Switches
==================
At the top of main.asm, you will find 3 switches:
USETABLES - enables tables
USEDRUMS - enables click drums
USELOOP - enables looping
Set any of these switches to 0 to disable the feature. This will reduce the
player size. Disabling tables will reduce the player size by 63 bytes, disabling
click drums will reduce the size by 99 bytes, and disabling looping will reduce
the size by 5 bytes.********************************************************************************
fluidcore
by utz 03'2016
********************************************************************************
ABOUT
=====
fluidcore is a 4 channel PCM wavetable player for the ZX Spectrum beeper, using
looped 256 byte waveforms. It offers a total of 17 volume levels, and can
handle up to ~860% overdrive when the maximum volume level is exceeded. Sound is
mixed at approximately 23 KHz.
VERSIONS
========
fluidcore comes in two versions - for NMOS and CMOS Z80 CPUs. Most original ZX
models use an NMOS CPU, most clones use a CMOS CPU. It's easy to tell which CPU
your Spectrum is sporting - if you get no sound and/or white stripes in the
border area with the NMOS version, you've got a CMOS CPU. For emulators, the
NMOS version will usually be the right choice.
Furthermore, sources are also included for a version that automatically detects
the MOS type and patches the code accordingly. It will however fail to detect
CMOS Z80 on models without an AY chip. To use this version, back up main.asm,
and rename main-autodetect.asm to main.asm.
REQUIREMENTS
============
You'll need the pasmo assembler installed or present in your search path in
order to use the XM converter.
When building from source, you'll also need to compile xm2fluid.cpp and
zmakebas.c.
COMPOSING MUSIC
===============
You can compose music using the provided music.xm template in conjunction with
the xm2fluid utility. This will only give a rough approximation of how the music
will sound on an actual or emulated ZX Spectrum, however.
The following restrictions apply:
- You cannot change the BPM.
- Instrument settings are ignored, except for partial mapping support (see
below)
- The volume column is ignored.
- Notes C-0 - G#0 have a special function, see below.
Furthermore, all effects are ignored, except:
- Bxx (jump to order - can be used to set the loop point)
- E5x (finetune - pitch translation isn't very accurate however)
- Fxx (change speed), with xx being in the range of 0x01-0x1f
The available instruments have their volume level stated in the name. If the
total volume level of the instruments in a given pattern row exceed 17, sound
will be overdriven. The XM template does not reflect this. The total volume
level on a given row must not exceed 146.
Certain instruments, like kicks and noise, are meant to be played at specific
fixed pitches. This can be achieved by using notes in the lowest octave, from
C-0 to G#0. Their pitch is not accurately represented in the XM template.
Furthermore, pitch will affect these instruments (especially noise) in a
non-linear fashion - again, the XM template does not reflect this behaviour. As
a general guideline, kicks will retrigger after 16 ticks at C-0, after 8 ticks
at D-0, after 4 ticks at E-0, and even faster on higher notes. Drums and noise
are also retriggered on every pattern row (as are all other instruments).
When you're done with composing, simply run the provided compile.cmd resp.
compile.sh scripts to convert your XM file into two ZX Spectrum .tap files -
one for NMOS and one for CMOS models (see "About" section for details).
compile.cmd/.sh will accept the following optional parameters (in the exact
order listed here):
-t "song title"
-c "composer name"
-a address*
Example: compile.cmd -t "My Song" -c "Great Musician"
This will create a BASIC screen which reads "My Song by Great Musician".
Alternatively, you can use interactive-compile.cmd/.sh to interactively set
these parameters.
* For ideal size, the compile address should be calculated with the formula
"N * 0x100 + 0x60", where N is a number higher than 0x80. So good choices are
0x8060 (32864), 0x8160 (33120), 0x8260 (33376), etc. When using main-
autodetect.asm, the magic formula is "N * 0x100 + 0x5a".
HINTS:
- To disable looping, uncomment line 48 in main.asm.
- If you're not satisfied with the standard speed settings, try playing with
the values in lines 69, 78, and 143 of main.asm. The following restrictions
apply:
- the value in lines 69 and 78 must be the same, and must be an odd value.
- the value in line 143 must be exactly one less than the one used in lines
69/78.
- the value in line 143 must have bits 4 and 5 set.
ADDING SAMPLES
==============
You can add your own wavetables/samples to the player. Samples must be exactly
256 bytes long, and must be put into the /samples subfolder. Check the included
ones for further details.
In order to add samples to the XM template/converter, you must do the following:
1) Append the sample's name to samplelist.txt.
2) Include a render of the sample in music.xm - the according instrument
position must be the same as in samplelist.txt.
You can use the following procedure for rendering samples:
1) Add a blank instrument in music.xm
2) Create a pattern with a single C-4 note of that instrument
3) Compile the song, run it in an emulator, and record the sound
4) Import the recorded sound to the blank instrument in music.xm, and enable
looping in the sample editor.
MUSIC DATA FORMAT
=================
Music data is split into two sections, song sequence and pattern data.
The song sequence must come first. It is a list of pointers to the actual note
patterns, in the order in which they are played. The sequence is terminated by
a 0-word. At some point in the sequence you must specify the label "loop", which
is where the player will jump to after it has completed the sequence. The
shortest possible sequence would thus be:
loop
dw ptn00
dw 0
Note: For technical reasons, the XM converter defines the loop label as an
equate at the end of the music data.
Following this are the note patterns. Each row in the patterns consists of 7
words, resp 14 bytes.
word 1: speed * 256 + 0 (flags, reserved for further use)
word 2: frequency ch1
word 3: frequency ch2
word 4: <hi-byte sample pointer ch1> * 256 + <hi-byte sample pointer ch2>
word 5: frequency ch3
word 6: frequency ch4
word 7: <hi-byte sample pointer ch3> * 256 + <hi-byte sample pointer ch4>
In order to mute a channel, simply set the frequency to 0, and the sample to
"instr0".
Note patterns are terminated with a $40 byte.
CREDITS
=======
All code by utz^irrlicht project, except:
- The MOS detection code was supplied by introspec, based on an idea by JtN.
- The ZMakeBas utility used by the xm2fluid converter is by Russell Marks.
********************************************************************************
www.irrlichtproject.de
********************************************************************************sq50-v1.asm
sq50-v2.asm
sq50-v3.asm
sq50-v4.asm
sq50-v5.asm
sq25-v1.asm
sq25-v2.asm
sq25-v3.asm
sq25-v4.asm
sq25-v5.asm
tri-v2.asm
tri-v4.asm
tri-v5.asm
tri-v6.asm
tri-v8.asm
saw-v3.asm
saw-v4.asm
saw-v5.asm
sine-v5.asm
sine-v8.asm
phat-v2.asm
phat-v4.asm
phat2-v4.asm
phat3-v3.asm
ice-v4.asm
ice2-v4.asm
kick-v1.asm
kick-v2.asm
kick-v3.asm
kick-v4.asm
kick-v5.asm
kick-v6.asm
whitenoise-v1.asm
whitenoise-v2.asm
whitenoise-v3.asm
whitenoise-v4.asm
whitenoise-v5.asm
whitenoise-v6.asm********************************************************************************
nanobeep by utz 09'2015 - 04'2016
2 channel beeper engine for ZX Spectrum
********************************************************************************
About
*****
nanobeep is a tiny beeper engine with minimalistic features. It features two
channels of PFM-synthesized tone, with rather large pin pulses. In addition,
there is a single interrupting click drum.
nanobeep comes in three different versions: regular, light, and ultra.
The "ultra" version is just 56 bytes long. However, it does cut some corners in
order to achieve that size. Namely, there is no loop support, no click drum, and
the screen border is not masked. Also, concurrent pin pulses are not duplicated,
meaning that when playing notes whose frequencies are multiples of each other
(for example, C-2 and C-3), the lower note will not be played.
The "light" player is 73 bytes. It adds border masking, loop support, and the
click drum. However, it still does not duplicate concurrent pulses, so it
suffers from the same issue as the "ultra" version in that respect.
The regular version is 77 bytes. This one has slightly better sound, as it
properly duplicates concurrent pulses.
Only keys Space, A, Q, and L will be checked. A full keyboard check can be added
at the cost of just 2 additional bytes. See the source for details on how to
implement this.
Requirements
************
The following tools are required to convert an XM track to a nanobeep binary:
- an XM tracker, for example Milkytracker (http://milkytracker.org)
- pasmo or a compatible Z80 assembler (http://pasmo.speccy.org)
- Perl (http://www.perl.org/get.html)
pasmo and Perl must be installed in your search path, or must reside within the
nanobeep folder.
Composing Music
***************
You can compose music for the nanobeep routine using the provided XM template.
This gives only a rough estimate of how the music will sound on an actual
ZX Spectrum though.
When using the XM template, consider the following:
- The number of channels cannot be changed.
- Changing the BPM setting has no effect, and tempo can be set only globally.
- You can use effect E5x (detune) on tone channels. All other effects will be
ignored.
- Tones must be in channel 1 or 2. The click drum must be in channel 3 or 4.
- You can use any note from C-0 to B-4. However, low notes will be detuned, and
notes in the 4th octave exceed the Nyquist limit, possibly leading to some
rather strange effects.
By default, the player will loop back to the start of the song. You can change
the loop point manually, by moving the "loop" label in music.asm to another
row in the sequence. You can disable looping altogether by uncommenting line 28
in main.asm.
When you're done with composing, simply run one of the provided compile
scripts. This will convert your XM file into a ZX Spectrum .tap file. To
convert only the XM file, run xm2nanobeep.pl. To produce the correct data for
the "ultra" version of the player, you must run xm2nanobeep.pl with an
additional "-u" argument.
Data Format
***********
nanobeep music data defines a 16-bit tempo value at offset 0. The higher the
value, the slower the tempo.
This is followed by the song sequence. The song sequence is a list of pointers
to the actual note patterns, in the order in which they are played. Pointers
must be offset by -1.
The sequence is terminated by a 0-word. At some point in the sequence you must
specify the label "loop", which is where the player will jump to after it has
completed the sequence. The shortest possible sequence would thus be:
loop
dw ptn00-1
dw 0
Following this are the note patterns. Each row in the patterns consists of 2-3
bytes.
Byte 1 is the drum and always has the value $fe. This byte is omitted if no
drum is to be played. In the "ultra" version, this byte is always omitted.
Bytes 2 and 3 are the note vales for channel 2 and 3, respectively.
In order to mute a channel, simply set the frequency to 0.
Note patterns are terminated with a $ff byte.********************************************************************************
nanobeep2
by utz 08'2017 * www.irrlichtproject.de
********************************************************************************
ABOUT
=====
nanobeep2 is a tiny sound engine for the ZX Spectrum beeper. Unlike the original
nanobeep, the design goal was not to make the player as small as possible, but
to cram in as much features as possible in less than 100 bytes.
In it's most basic form, the player takes up 64 bytes of memory. A range of
additional features can be activated via assembler switches, increasing the size
of the player up to a maximum of 99 bytes.
Core (minimal) player features:
- 2 square wave channels
- global 8-bit tempo resolution
- 8-bit note dividers (~4 octaves, lowest notes may be detuned)
- limited keyboard checking (checks only Space, A, L, Q)
Additional features:
- border masking
- full keyboard checking
- PWM sweep sound
- click drum
- per-pattern tempo setting
- increased note range (6 octaves)
USAGE
=====
There is currently no dedicated editor for the engine, so the only way to make
music for it is to code it directly in assembly.
The player code should be compiled with PASMO.
ASSEMBLER SWITCHES
==================
borderMasking
Mask the coloured stripes in the border. Costs 4 bytes extra, or 6 bytes if the
click drum is also enabled.
fullKeyboardCheck
Implements a full keyhandler that will check all keys. Costs 1 byte extra.
loopToStart
Loop back to the start instead of exiting at the end of a tune. Costs 0 bytes.
pwmSweep
Use a SID-like PWM sweep sound instead of plain square wave for channel 1. Costs
2 bytes.
useDrum
Add a simple interrupting hi-hat like click drum. Tempo offset is not corrected.
Costs 11 bytes.
usePatternSpeed
Allow setting a different tempo value for each pattern. Costs 4 bytes, plus 2
bytes per pattern.
usePrescaling
Allow channels to be shifted 1 octave up or down, effectively increasing the
note range to 6 octaves. Can be set per pattern. Costs 11 bytes, plus 2 bytes
per pattern.
DATA FORMAT
===========
The music data format uses the usual sequence-pattern approach. A sequence of
pattern pointers (in the order in which they are meant to be played) is followed
by one or more patterns, containing the actual note data.
Sequences must be terminated with a 0-word.
If the usePatternSpeed switch is disabled, you must specify an equate for
"speed" (0x1..0xff, higher value means slower speed).
Pattern structure is as follows:
1) If the usePatternSpeed switch is enabled, speed is set with a 0-byte,
followed by the actual speed value (higher means slower speed).
2) If the usePrescaling switch is enabled, two bytes specifying the prescaling
for channel 2 and channel 1 follow. Legal values are 0xf (scale down), 0x0
(no scaling), and 0x7 (scale up).
3) One or more rows of note data follow. First byte sets the note for channel 1,
second byte sets channel 2. If the useDrum switch is enabled, then the first
byte is set to 0xfe to trigger the drum sound, followed by note data for ch1
and ch2. On rows with no drum, the drum data byte is omitted. Legal note
values are 0x1 - 0xfd. 0x0 specifies a rest.
4) Mandatory pattern end marker, a single 0xff byte follows.
***********************************************************************************************
NTROPIC music routine for ZX Spectrum
by utz 01'2014, revised 08'2014
***********************************************************************************************
2 square wave channels, 1 noise channel, drums
Requirements:
=============
In order to use ntropic, you will need
- pasmo or another Z80 assembler of your choice
- Perl for compiling the music from an XM file
- Milkytracker or another XM tracker for writing music
Writing Music
=============
You can compose music using the included music.xm template. It gives only a rough impression of
how the music will sound on actual hardware though.
You can set the song speed with the global "Spd" setting, or at any given point with command
Fxx. BPM settings are ignored.
Notes go in tracks 1 and 2. You can use notes from C#0 to B-7. However, notes in higher octaves
are prone to detuning, which is not reflected in the xm template.
You can use manual detune on both tone channels with command E5x.
Track 3 is the noise channel. The pitch is ignored. You can set the length with command ECx.
Note that this gives only a rough estimate on how long the noise will sound.
You can put the drum in any channel, it's pitch will be ignored.
All other effect commands are ignored.
Compiling
=========
Provided you have Perl and pasmo installed on your system, simply run the
compile.bat resp. compile.sh scripts.
ntropic Music Data Format
==========================
You can also code the music.asm file by hand, if you like. The music data consists of an
order list containing the sequence of patterns, followed by the pattern data itself.
The order list must be ended with dw #0000, patterns must end with db #ff.
byte 1 = speed+drum or pattern end marker (#ff)
drum can be 0 (no drum), or 1 (kick)
speed can be #04..#fc, must be a multiple of 2
bytes 2-3 = tone counters ch1-ch2
values are inverse, ie. higher value means lower tone
byte 4 = noise length
values can 0-#30, 0 = off
********************************************************************************
Octode 2k15 beeper routine for ZX Spectrum
by utz 09'2015
original code by Shiru 02'11
"XL" version by introspec 10'14-04'15
********************************************************************************
Features
********
Octode 2k15 is a rewrite of the original Octode engine by Shiru, resp. the "XL"
mod by introspec. The player has been modified to avoid the detuning issues
found in these earlier versions.
- 8 channels with PFM (pin pulse) sound
- 16-bit frequency precision
- variable duty cycle
- per-step speed control
- 3 interrupting click drums
Requirements
************
The following tools are required to use the xm2octode2k15 utility
- an XM tracker, for example Milkytracker (http://milkytracker.org)
- pasmo or a compatible Z80 assembler (http://pasmo.speccy.org)
- Perl (http://www.perl.org/get.html)
pasmo and Perl must be installed in your search path, or must reside within the
octode2k15 folder.
Composing Music
***************
You can compose music for the Octode 2k15 player using the XM template that
comes bundled with Octode2k15. However, this will only give a very rough
estimate of how the music will sound on an actual ZX Spectrum.
When using the XM template, consider the following:
- You may not change the number of channels.
- Notes must be in channel 1-8.
- Drums must be in channel 9-10, and you cannot set more than one drum per row.
- Changes to the BPM value or to the instruments have no effect.
- You may change the speed value globally, or at any point by using command Fxx,
where xx must be in the range of 0-$1f.
- The note range is limited from C-0 to B-5.
- You may set note detune with command E5x.
- All other effect commands, as well as volume settings will be ignored.
- The music data is rather large, so song length is limited to ~30 64-step
patterns.
By default, Octode 2k15 modules loop back to the start. You can change this
manually by moving the "loop" label in music.asm to another position in the
sequence. To disable looping entirely, uncomment line 37 in main.asm.
When you're done composing, simply run the provided compile.bat (Win) resp.
compile.sh scripts to generate a .tap file of your music. If you only want to
generate the music data, run xm2octode2k15.pl without any arguments.
Data Format
***********
Octode 2k15 music data consists of a song sequence, followed by the pattern data.
The song sequence is a list of pointers to the actual note patterns, in the order
in which they are played. The sequence is terminated by a 0-word. At some point
in the sequence you must specify the label "loop", which is where the player will
jump to after it has completed the sequence. The shortest possible sequence would
thus be:
loop
dw ptn00
dw 0
Following this are the note patterns. Each row in the patterns consists of 9
words (18 bytes).
word 1: speed * 256 + drum triggers (1 = kick, 5 = snare, $81 = hihat)
word 2: frequency ch8
word 3: frequency ch1
word 4: frequency ch2
word 5: frequency ch3
word 6: frequency ch4
word 7: frequency ch5
word 8: frequency ch6
word 9: frequency ch7
In order to mute a channel, simply set the frequency to 0.
Note patterns are terminated with a single $40 byte.
********************************************************************************
Octode 2k16 beeper routine for ZX Spectrum
by utz 05'2016
original code by Shiru 02'11
"XL" version by introspec 10'14-04'15
********************************************************************************
About
=====
Octode 2k16 is yet another rewrite of the Octode beeper routine (written by
Shiru in 2011). More accurately, it is a rewrite of Octode PWM with cleaner
sound and an improved frequency range. However, unlike Octode PWM it does not
feature variable duty cycles.
- 8 channels with square wave sound
- 16-bit frequency precision
- per-step speed control
- 3 interrupting click drums
- drum volume can be controlled to some extend
Octode 2k16 comes in two versions - for NMOS and CMOS Z80 CPUs. Most original
ZX models use an NMOS CPU, most clones use a CMOS CPU. It's easy to tell which
CPU your Spectrum is sporting - if you get no sound and/or white stripes in the
border area with the NMOS version, you've got a CMOS CPU. For emulators, the
NMOS version will usually be the right choice.
Requirements
============
The following tools are required to use the xm2octode2k16 utility
- an XM tracker, for example Milkytracker (http://milkytracker.org) or OpenMPT
(http://openmpt.org)
- pasmo or a compatible Z80 assembler (http://pasmo.speccy.org)
pasmo must be installed in your search path, or must reside within the
octode2k16 folder.
Composing Music
===============
You can compose music for the Octode 2k16 player using the XM template that
comes bundled with Octode 2k16. However, this will only give a very rough
estimate of how the music will sound on an actual ZX Spectrum.
When using the XM template, consider the following:
- You may not change the number of channels.
- Tones must be in channel 1-8.
- The note range is limited from C-0 to B-6. Beware that notes above C-5 will
be aliased.
- Drums should be in channel 9-10, and you can only use one drum per row.
- Drums have a fixed pitch, mapped to C-4 in the template.
- You can use the volume column to set the drum's volume. This is most effective
on the hihat, it has little effect on the kick.
- Changes to the BPM value or to the instruments have no effect.
- You may change the speed value globally, or at any point by using command Fxx,
where xx must be in the range of 0-$1f.
- You may set note detune with command E5x.
- You may set the sequence loop point with command Bxx.
- All other effect commands, including volume settings on tones will be ignored.
By default, Octode 2k16 will loop until a key is pressed. To disable looping,
uncomment line 53 in main.asm.
When you're done with composing, simply run the provided compile.cmd resp.
compile.sh scripts to convert your XM file into two ZX Spectrum .tap files -
one for NMOS and one for CMOS models (see "About" section for details).
compile.cmd/.sh will accept the following optional parameters (in the exact
order listed here):
-t "song title"
-c "composer name"
-a address*
Example: compile.cmd -t "My Song" -c "Great Musician"
This will create a BASIC screen which reads "My Song by Great Musician".
Alternatively, you can use interactive-compile.cmd/.sh to interactively set
these parameters.
Data Format
===========
Octode 2k16 uses a somewhat unusual data format. It follows the common sequence-
pattern approach, but stores the actual note data in seperate row-length
buffers.
The song sequence must follow directly after the musicData label (that is, at
the top of music.asm). It consists of a list of pointers to the actual patterns,
in the order in which they are played. The sequence is terminated by a 0-word.
At some point in the sequence you must specify the label "loop", which is where
the player will jump to after it has completed the sequence.
Patterns and row buffers can be located anywhere in the music data. If memory
is sparse, you could even squeeze data into the gaps between the 8 sound cores.
Patters consist of one or more rows, which in turn contain 2-3 word length
entries. The first word is the control word, which is constructed as
(row speed * 256) + drum trigger. Drum triggers are
0x00 - no drum
0x01 - hihat
0x04 - kick
0x80 - snare
If the drum trigger is not zero, the next word is the drum volume. The high
byte of this is always 0, the low byte can be any value. A value of 0x80
signifies the highest volume, both lower and higher values signify lower
volumes.
The last word is a pointer to a row buffer, containing the actual note data
for the given pattern row.
Patterns must be terminated with 0x40.
Last but not least, there should be at least one row buffer. Row buffers
consist of 8 words, representing 8 frequency (counter) values. To silence a
channel, simply set it's frequency to 0. Row buffers do not need to be
terminated.
A minimal song data set would thus look like this:
loop
dw pattern
dw 0
pattern
dw #1001,#0080,row
db #40
row
dw #200,#400,#300,#0,#0,#0,#0,#0
********************************************************************************
Octode PWM beeper routine for ZX Spectrum
by utz 09'2015
original code by Shiru 02'11
"XL" version by introspec 10'14-04'15
********************************************************************************
Features
********
Octode PWM is a rewrite of the original Octode engine by Shiru, resp. the "XL"
mod by introspec. The player has been modified to avoid the detuning issues
found in these earlier versions.
- 8 channels with square wave sound (sort of)
- 16-bit frequency precision
- variable duty cycle
- per-step speed control
- 3 interrupting click drums
Requirements
************
The following tools are required to use the xm2octodepwm utility
- an XM tracker, for example Milkytracker (http://milkytracker.org)
- pasmo or a compatible Z80 assembler (http://pasmo.speccy.org)
- Perl (http://www.perl.org/get.html)
pasmo and Perl must be installed in your search path, or must reside within the
octodepwm folder.
Composing Music
***************
You can compose music for the Octode PWM player using the XM template that
comes bundled with Octode PWM. However, this will only give a very rough
estimate of how the music will sound on an actual ZX Spectrum.
When using the XM template, consider the following:
- You may not change the number of channels.
- Notes must be in channel 1-8.
- Drums must be in channel 9-10, and you cannot set more than one drum per row.
- Changes to the BPM value or to the instruments have no effect.
- You may change the speed value globally, or at any point by using command Fxx,
where xx must be in the range of 0-$1f.
- The note range is limited from C-0 to B-3.
- You may set note detune with command E5x.
- All other effect commands, as well as volume settings will be ignored.
- The music data is rather large, so song length is limited to ~30 64-step
patterns.
By default, Octode PWM modules loop back to the start. You can change this
manually by moving the "loop" label in music.asm to another position in the
sequence. To disable looping entirely, uncomment line 37 in main.asm.
When you're done composing, simply run the provided compile.bat (Win) resp.
compile.sh scripts to generate a .tap file of your music. If you only want to
generate the music data, run xm2octodepwm.pl without any arguments.
Data Format
***********
Octode PWM music data consists of a song sequence, followed by the pattern data.
The song sequence is a list of pointers to the actual note patterns, in the order
in which they are played. The sequence is terminated by a 0-word. At some point
in the sequence you must specify the label "loop", which is where the player will
jump to after it has completed the sequence. The shortest possible sequence would
thus be:
loop
dw ptn00
dw 0
Following this are the note patterns. Each row in the patterns consists of 9
words (18 bytes).
word 1: speed * 256 + drum triggers (1 = kick, 5 = snare, $81 = hihat)
word 2: frequency ch1
word 3: frequency ch2
word 4: frequency ch3
word 5: frequency ch4
word 6: frequency ch5
word 7: frequency ch6
word 8: frequency ch7
word 9: frequency ch8
In order to mute a channel, simply set the frequency to 0.
Note patterns are terminated with a single $40 byte.
********************************************************************************
PhaserX
by utz 09'2016 * www.irrlichtproject.de
********************************************************************************
ABOUT
=====
PhaserX is an experimental 2-channel beeper engine for the ZX Spectrum. It uses
a new type of effect called "duty modulation". As the name suggests, this effect
modulates the duty cycle setting over time. Its operating speed is synced to the
affected tone generator, so despite the similarities with the tone generation in
engines like Earth Shaker, it does not affect pitch.
Each of the two tone channels has a different set of effects. Channel 1 produces
a simple square wave. In addition to the aforementioned duty modulation, it
features a SID-like duty cycle sweep effect, and can generate pseudo-white noise
instead of square waves.
Channel 2 uses two oscillators to produce Phaser-style sound. Each of the
oscillators can have it's own duty modulation settings. This allows for very
complex timbres. Oscillator frequencies can of course be configured
independantly, and can run at different phases. The channel mixer supports XOR
(Phaser1 standard), OR, and AND mixing methods. When using the OR method, the
oscillators can be decoupled and used as 2 independant channels, Squeeker style.
Credits go to Shiru for inventing the original Phaser effect.
Note that the engine does not check for Kempston interface presence.
COMPOSING
=========
There is currently no editor available for this engine, so in order to use it,
you'll have to hack up the music in Assembly. For details, check out the example
music.asm file, and the equates.h header.
MUSIC DATA
==========
The music data layout follows the usual sequence-pattern model.
The sequence is a list of pointers to patterns, in the order in which they are
to be played. A "loop" label must be present to specify which position the
player will loop to once the end of the sequence is reached. The sequence must
be terminated with a 0-word. Hence, the shortest possible sequence looks like
this:
loop
dw pattern
dw 0
Pattern data has a dynamic layout, using 2-9 words per row. Their function is
as follows:
1) speed (ticks_per_row * 256) + drum flags (1 = kick, 0x80 = hihat)
2) ch2_mixing_method * 256 + control flags
mixing methods: 0xac = XOR, 0xb4 = OR, 0xa4 = AND
ctrl flags: 1 = no update ch1, 0x40 = no update ch2
4 = enable SID, 0x80 = enable noise
3) duty_modulator_ch1 * 256 + duty_ch1
4) note_divider_ch1
5) duty_modulator_ch2_oscA * 256 + duty_modulator_ch2_oscB
6) duty_ch2_oscA * 256 + duty_ch2_oscB
7) note_divider_ch2_oscA
8) note_divider_ch2_oscB
9) phase_offset_ch2_oscB
When the "no update ch1" flag is set, words 3 and 4 are omitted.
When the "no update ch2" flag is set, words 5-9 are omitted.
Initialization is mandatory for both channels at the beginning of the song.
Channel 2 must be updated at the beginning of each pattern.
Patterns are terminated with a 0x40 byte.
********************************************************************************
Phase Squeek, aka TOUPEE (Totally Overpowered, Utterly Pointless Extreme Engine)
by utz 08'2016 | www.irrlichtproject.de
********************************************************************************
ABOUT
=====
Phase Squeek is ZX Spectrum beeper music routine with a rather complex synth
core based on an unholy fusion of Shiru's Phaser method with zilogat0r's Sqeeker
method.
The engine can be configured in different ways. In it's standard configuration,
it sports two channels, each using two operators coupled together. However, the
operators can also be decoupled and act as independant channels (so up to four-
voice polyphony is possible). Or you can couple both standard channels together
to form a single, all powerful voice.
While operators are coupled, the following settings can be customized on each
channel:
- frequency (independant dividers for each operator)
- duty cycles (independantly for both ops)
- operator phase
- coupling method (XOR|OR|AND - OR effectively decouples the operators)
Additionally, channel 1 supports the following settings:
- SID-style duty cycle modulation (independantly for both ops)
- Earth Shaker style duty cycle modulation (independantly for both ops)
Channel 2 instead offers a noise mode for operator 1.
All settings can be updated not only between notes, but also on a per-tick basis
via effect tables.
Last but not least, two interrupting click drums are also available.
COMPOSING MUSIC
===============
Unfortunately, the engine is too complex to be simulated via an XM template, and
it is currently not supported by any beeper editors either. So, for the time
being, music can only be hand-coded in asm. Refer to the music data description
for further details.
MUSIC DATA
==========
Phase Squeek's music data follows the usual sequence-pattern approach, with the
addition of one or more fx tables.
The sequence must be at the start of the data section. It is a simple list of
pointers to the patterns, in the order in which they are to be played. It is
terminated with a 0-word. A label named "loop" must also be present, this
specifies the sequence position to which the player will jump once the sequence
has been completed. The shortest valid sequence is thus:
loop
dw pattern0
dw 0
Patterns use a flexible layout, the details of which are determined by one or
more control words.
The format is a follows:
________________________________________________________________________________
1) ctrl_0 (mandatory for each row)
bit set function
0 skip FX table pointer update
2 skip updates for this row -> continue with ctrl_3
6 end of pattern
7 skip updates for channel 1 -> continue with ctrl_2
8..15 global coupling method, can be one of
a0 - AND
a8 - XOR
b0 - OR (channels decoupled)
If bit 0 is reset, a word-length pointer to an FX table follows.
________________________________________________________________________________
2) ctrl_1
bit set function
0 skip update of frequency channel 1 operator 1/2
2 skip update of SID/Earth Shaker effects ch1 op1/2
6 skip update of duty cycle setting ch1 op1/2
7 skip update of phase ch1
8..15 ch1 operator coupling method, see ctrl_0
If bit 0 is reset, two word-length frequency divider values follow.
If bit 6 is reset, duty_setting_ch1op1 * 256 + duty_setting_ch1op2 follows.
If bit 2 is reset, two words specifying the SID/ES effect settings follow.
ES effect takes an arbitrary 8-bit value as argument. 0 disables the effect.
To enable the SID effect, add 0xce00.
To disable the SID effect, add 0xc600.
If bit 7 is reset, a word specifying the phase offset of ch1 op1 follows.
Note that setting the duty to a value greater than 0x40 or activating the SID
effect on both operators can overload the engine (ie ch2 may be drowned out).
________________________________________________________________________________
3) ctrl_2
Same as for ctrl_1, but specifying parameters for ch2 instead. There is one
exception, however: Setting bit 2 enables the noise generator on ch2 op1 (in
which case it should be fed a suitable seed value via ch2 op1 frequency - 0x2175
usually does a good job). Resetting bit 2 disables the noise generator.
________________________________________________________________________________
4) ctrl_3 (mandatory for each row)
bit set function
6 trigger click drum 1 (kick)
7 trigger click drum 2 (hihat) if bit 6 was reset
8..15 speed (row length in ticks)
________________________________________________________________________________
NOTE: The first row of the first pattern in the song must set all parameters.
The FX table layout is almost the same as the pattern layout. Notable
differences are:
- all operations take effect on fixed-length frames (aka ticks) rather than
pattern rows.
- ctrl_3 is omitted.
- ctrl_0 has the following changes:
bit set function
0 modify FX table pointer. This can be used to create a table loop, or
to jump to another FX table.
6 stop FX table execution.
If bit 0 is set, a word-length pointer to an FX table location must follow.
VERSION HISTORY
===============
0.1 initial public release
eof.********************************************************************************
povver v0.1 - 3 channel beeper engine with volume control
by utz 11'2016
********************************************************************************
About
=====
povver is an experimental 3-channel beeper engine for the ZX Spectrum. It
features a simple volume control mechanism which is achieved through dual
oscillators running with a phase offset. The results are perhaps not as
impressive as what can be achieved through digital multi-core synthesis, but
it consumes much less RAM.
Aside from volume control, povver also features
- simple volume envelopes
- noise mode for channel 1
- customizable click drums
- per step tempo control
- compact music data format
Composing Music
===============
Currently, no editor exists for povver, so any music must be hand-crafted as
assembly data. See the following section on how to construct the necessary
music.asm files.
Data Format
===========
Music data for povver follows the usual sequence-pattern approach.
The sequence contains one or more pointers to patterns, in the order in which
they are to be played. A label named "mLoop" must be present in the sequence to
determine the position the player will loop to after it has completed the
sequence. (To disable looping, uncomment lines 27-28 in main.asm.) The sequence
must be terminated with a 0-byte. The shortest legal sequence is thus:
mLoop
dw pattern
dw 0
Patterns contain the actual musical score. povver uses a rather compact scheme
word bit function
==========================================================================
0 tempo*256|flags
0 skip update ch1
2 skip update ch2
6 end of pattern (see below)
7 skip update ch3
8..15 tempo (row length as number of ticks/frames)
1 freq_div1|volume|envelope_flag (omitted when word 0, bit 0 set)
0..10 frequency divider ch1
11..14 initial phase offset (volume) ch1. 0 = loudest, #f = quietest
15 enable volume envelope ch1
2 as above, but for ch2 (omitted when word 0, bit 2 set)
3 as above, but for ch3 (omitted when word 0, bit 3 set)
4 drum|noise_enable
0 trigger kick
2 trigger hihat
Only one drum trigger can be used per row.
6 enable noise mode ch1 (requires suitable seed as freq_div1)
8..15 set click drum parameters
for kick, bit 8..15 = initial pitch (higher value = higher pitch)
for noise, bit 8 sets type (lower pitch if set), bit 9..15 sets
volume (higher value = louder)
The first pattern in the sequence must set all parameters.
Word 1 must be set at the start of each pattern.
Each pattern must end with a pattern end flag (#40).
POWW - a 1-bit music routine for ZX Spectrum
written by utz 05'2013
www.irrlichtproject.de
report bugs and suggestions to utz AT my domain
HOW TO USE
There is no dedicated editor for this engine, so you can only make music by editing music.asm directly.
After you've composed your song, assemble poww.asm. I use pasmo for this ($ pasmo -d --tap poww.asm poww.tap),
though the code should be easily adaptable for other assemblers as well.
Note values are inverse, ie. higher values mean lower pitches.
There is no note to pitch conversion, you'll have to figure out the correct values yourself.
Note data is linear, ie. no patterns etc.
The data layout is as follows
db nn,mm,oo,pp
where nn is the drum byte (0 = no drum, 1 = kick, 2 = snare)
mm is the instrument setting for channel 1.
oo is the note byte for channel 1 (see below for pitch limits, 0 = mute)
pp is the note byte for channel 2 (can be any value, 0 = mute)
Possible instruments for channel 1 are:
0 - Instrument 1 - max. note val 28
11 - Instrument 2 - max. note val 42
22 - Instrument 3 - max. note val 25
33 - Instrument 4 - max. note val 42
44 - Instrument 5 - max. note val 42
55 - Instrument 6 - max. note val 63
66 - Instrument 7 - max. note val 36
77 - Instrument 8 - max. note val 31
88 - Instrument 9 - max. note val 28
99 - Instrument 10 - max. note val 28
You can use other instrument values, too, but this will cause detuning and destabilize timing.
You can make your own instruments by adding lines to the pwm-table (@pw0 in poww.asm).
Lines must be 11 bytes long, and the sum of all values must be 36.
You can change the song speed by editing line 14 of poww.asm. The value should be at least twice as high as
the value of your lowest note on channel 1. Normally you'll want to keep speed above #80.
PYTHA
by utz 06'2017
********************************************************************************
About
=====
Pytha is a two-channel music routine for the ZX Spectrum beeper. It is the first
beeper engine to synthesize triangle waves without the use of wavetables.
Features:
- supported waveforms: triangle, saw, rectangle with arbitrary duty cycle, noise
- LFO-powered modulation effects
- 3 customizable click drums (interrupting)
- 16-bit frequency resolution, 8-bit speed resolution
Composing Music
===============
There is currently no dedicated editor for Pytha. For the time being, the only
choice is to write music directly in Assembly language.
Data Format
===========
Music data for Pytha follows the usual sequence-pattern approach. A sequence,
constituting the order list of the song, is followed by one or more pattern
blocks containing the actual note data.
The sequence contains a list of pointers to individual patterns, in the order in
which they are meant to be played. The sequence is terminated with a 0-word.
Unless looping is disabled (by setting USE_LOOP to 0 in main.asm), the sequence
must contain an "mloop" label, which specifies to the point to which the player
will loop after the sequence has been completed. The shortest legal sequence is
therefore:
mloop
dw pattern1
dw 0
Patterns contain one or more rows of note data, which are parsed in consecutive
order.
Pattern rows consist of 1-8 words. These have the following function:
word bits function
____________________________________________________________________
0 global row flags and row length
mandatory for every row
0 if set, skip channel 2 update
2 if set, trigger click drum
6 if set, skip channel 1 update
7 end marker, see below
8..15 row length (speed)
____________________________________________________________________
1 drum configuration
omitted if bit 2 of word 0 is reset
0..7 drum parameter
if mode = kick, set the slide speed
if mode = noise, set the volume
8..14 if mode = kick, set starting pitch
14..15 set drum mode: 00 = kick
10 = noise hi (hihat)
11 = noise lo (snare)
____________________________________________________________________
2 flags and initial modulator offset channel 1
omitted if bit 6 of word 0 is set
0 if set, update only frequency divider
2 enable/disable noise mode
6 enable/disable modulator lfo
8..15 initial modulator offset
modulator and noise settings are ignored if
bit 0 is set
____________________________________________________________________
3 waveform channel 1
omitted if bit 6 of word 0 or bit 0 of word 2 is set
legal values: $ac9f = triangle
$009f = rectangle
$000f = saw
____________________________________________________________________
4 frequency divider channel 1
omitted if bit 6 of word 0 is set
____________________________________________________________________
5 flags and initial modulator offset channel 2
omitted if bit 0 of word 0 is set
0 if set, update only frequency divider
2 enable/disable noise mode
6 enable/disable modulator lfo
8..15 initial modulator offset
modulator and noise settings are ignored if
bit 0 is set
____________________________________________________________________
6 waveform channel 2
omitted if bit 0 of word 0 or word 5 is set
legal values see word 3
____________________________________________________________________
7 frequency divider channel 2
omitted if bit 0 of word 0 is set
All values must be set on the first row of the first pattern in the sequence.
Patterns must be terminated with an end marker, which is a single "db $80".
********************************************************************************
http://irrlichtproject.de
***********************************************************************************************
qaop - beeper music routine for ZX Spectrum
by utz 08'2015
***********************************************************************************************
qaop features two channels of arbitrary waveform (sample) playback, and some interrupting click
drums.
The routine must be assembled aligned to a 256-byte border.
Using the XM Converter
======================
Unfortunately, the included XM converter is very limited and does not provide an easy option to
add user-made samples.
In order to convert an XM song to a qaop binary, you'll need the following tools:
- an XM tracker, for example Milkytracker (http://milkytracker.org)
- pasmo or a compatible Z80 assembler (http://pasmo.speccy.org)
- Perl (http://www.perl.org/get.html)
pasmo and Perl must be installed in your search path, or must reside within the
nanobeep folder.
When using the XM template, consider the following:
- The number of channels cannot be changed.
- Changing the BPM setting has no effect, and tempo can be set only globally.
- Tones must be in channel 1 or 2. You can use any note from C-2 to B-6.
- You can use effect E5x (detune) on channels 1 and 2.
- You can use effect Fxx (tempo) anywhere. xx must be $01-$1f.
- All other effects are ignored.
- Click drums (instruments 1-3) must be in channel 3 or 4. There can only be one
click drum per row.
By default, the player will loop back to the start of the song. You can change
the loop point manually, by moving the "loop" label in music.asm to another
row in the sequence. You can disable looping altogether by uncommenting line 45
in main.asm.
When you're done with composing, simply run the provided compile.bat resp.
compile.sh scripts to convert your XM file into a ZX Spectrum .tap file. To
convert only the XM file, run xm2qaop.pl.
Adding New Samples to the Converter
===================================
There is no easy way of doing this, unfortunately. The procedure is as follows:
Step 1: Make a sample in qaop's native format (see next section for details)
Step 2: Append the sample to the @instruments array in xm2qaop.pl (near the end)
Step 3: Sample a C-4 note, and add it to the XM template. Sample looping should
be activated, of course.
qaop Sample Data Format
==========================
qaop lets you use your own samples, or rather looped waveforms. Samples must be included in
samples.asm. Check out the /samples folder for inspiration.
qaop samples have a fixed length of 256 bytes. The format is unsigned PCM, meaning all bytes
in the sample denote a relative volume. Bytes can take any value from 0 (silent) to 6 (loudest).
However, the maximum combined volume level of both channels is 6, so if you want to avoid
overdrive/distortion, do not use sample volumes >3. It's usually not a problem to use sample
volumes up to 4, though.
You can use the included wav2smp.pl script to convert unsigned raw (header-less) 8-bit PCM WAV
files to qaop .smp format.
qaop Music Data Format
==========================
The music data consists of an order list containing the sequence of patterns, and the pattern
data itself. The order list must be ended with dw #0000, followed by a loop point address.
Patterns must end with db #40.
Layout of the rows in pattern data is as follows:
offset length function
[+0 byte #40 = end marker]
+0 word speed*256 + click drum (0 = none, 1 = kick, 5 = snare, 81 = hihat)
+2 word frequency ch1
+4 word frequency ch2
+6 word sample addresses [hi-byte ch1*256] + [hi-byte ch2]
When using click drums, the speed must be manually decremented in the pattern data. Length and
pitch of the click drums can be manually adjusted in main.asm.
Trivia
======
qaop stands for "Quite Accurate Overdriven Player".
********************************************************************************
quattropic by utz 08'2015
4 channel beeper engine for ZX Spectrum
********************************************************************************
About
*****
quattropic offers 4 channels of square wave tone with variable pulse width. One
of the channels can be used play noise of varying length, pitch, and timbre.
Furthermore, you can activate a fast pitch slide on one of the channels to
produce percussive sounds. You can switch between the modes (tone/noise/slide)
on a step-by-step basis.
The quattropic package includes the ZMakeBas utility by Russell Marks.
Requirements
************
The following tools are required to convert an XM to a quattropic binary:
- an XM tracker, for example Milkytracker (http://milkytracker.org)
- pasmo or a compatible Z80 assembler (http://pasmo.speccy.org)
pasmo must be installed in your search path, or must reside within the
quattropic folder.
When compiling the quattropic package from source, you first need to build
xm2quattropic.cpp and zmakebas.c.
Composing Music
***************
You can compose music for the quattropic routine using the provided XM template.
This has a few drawbacks, however. First of all, the template gives only a rough
estimate of how the music will sound on an actual ZX Spectrum. Secondly, you can
not take care of the engine's full capabilities this way, as it would be too
complex to simulate via XM.
When using the XM template, consider the following:
- Do not change the number of channels.
- Changing the BPM setting has no effect.
- Instruments 1-4 (tone) can be in any channel.
- Instruments 5-8 (noise) can only be used in channel 4.
- Instruments 9-A (slide) can only be used in channel 3.
The pitch of the noise instruments impacts timbre, but not necessarily the
actual pitch. Also, octaves are disregarded for noise instruments. The XM
template does not accurately reproduce this behaviour.
The slide instruments (9, A) will reset on every row. This behaviour is not
reproduced in the XM template.
You can use effect ECx (note cut) on channel 4. You can also use effect E5x
(detune) on all of the channels. All other effects will be ignored.
Channels are not 100% equal in volume. Channel 3 is slightly louder than the
rest. There are only marginal differences between the other channels.
By default, the player will loop back to the start of the song. You can change
the loop point manually, by moving the "loop" label in music.asm to another
row in the sequence. You can disable looping altogether by uncommenting line 47
in main.asm.
When you're done with composing, simply run the provided compile.cmd resp.
compile.sh scripts to convert your XM file into a ZX Spectrum .tap file.
compile.cmd/.sh will accept the following optional parameters (in the exact
order listed here):
-t "song title"
-c "composer name"
-a address (must be a decimal number between 32768 and ~60000)
Example: compile.cmd -t "My Song" -c "Great Musician" -a 40000
This will create a BASIC screen which reads "My Song by Great Musician", and
assemble the player+data at address 40000.
Alternatively, you can use interactive-compile.cmd/.sh to interactively set
these parameters.
Data Format
***********
quattropic music data defines an 8-bit tempo value at offset 0. The higher the
value, the slower the tempo.
This is followed by the song sequence. The song sequence is a list of pointers
to the actual note patterns, in the order in which they are played. The
sequence is terminated by a 0-word. At some point in the sequence you must
specify the label "loop", which is where the player will jump to after it has
completed the sequence. The shortest possible sequence would thus be:
loop
dw ptn00
dw 0
Following this are the note patterns. Each row in the patterns consists of 7
words, resp 14 bytes.
word 1: (speed - note length) * 256 + play mode (0 = tone, 1 = noise,
4 = slide, $80 = noise+slide)
word 2: duty ch1 * 256 + duty ch2
word 3: duty ch3 * 256 + duty ch4 (duty can also be set for noise/slide)
word 4: frequency ch1
word 5: frequency ch2
word 6: frequency ch3
word 7: frequency ch4
In order to mute a channel, simply set the frequency to 0.
Note patterns are terminated with a $40 byte.***********************************************************************************************
RAWP music routine for ZX Spectrum
by utz 08'2014
***********************************************************************************************
2 custom waveform channels, hihat
Requirements:
=============
In order to use rawp, you will need
- pasmo or another Z80 assembler of your choice
- Perl for compiling the music from an XM file
- Milkytracker or another XM tracker for writing music
Writing Music
=============
You can compose music using the included music.xm template. It gives only a rough impression of
how the music will sound on actual hardware though.
You can set the song speed with the global "Spd" setting, or at any point with command Fxx. BPM
settings are ignored.
Instruments 01-11 go in tracks 1 and 2. You can in theory use notes from C-1 to B-7. However,
you may notice that the lower octaves are out of audible range with most instruments. Notes
in higher octaves are prone to detuning, which is not reflected in the xm template.
You can use manual detune on both tone channels with command E5x.
You can use effects 1xx/2xx in track 1 to activate pitch slide up/down. The effect parameters
are ignored. The speed of the pitch slide depends on the note counter value in channel 2. You
can use the dummy instrument (instrument 13) in track 2 to set the note counter for channel 2
without triggering an instrument. A higher notes means slower slide speed. The counter value
on channel 1 will wrap once it reaches 0 or 255, use short steps to avoid the retrigger.
It is ultimately impossible to emulate the actual effect in XM, so it is best edited manually
in the asm file. See data format section for details.
You can put the hihat (instrument 12) in any channel, it's pitch will be ignored.
You can specify the order loop point with command Cxx (not Bxx!) somewhere on an empty track.
All other effect commands are ignored. Except for Fxx/Cxx, effect settings affect the current
row only.
Compiling
=========
Provided you have Perl and pasmo installed on your system, simply run the
compile.bat resp. compile.sh scripts.
rawp Music Data Format
==========================
You can also code the music.asm file by hand, if you like. The music data consists of an
order list containing the sequence of patterns, and the pattern data itself.
The order list must be ended with dw #0000, followed by a loop point address.
Patterns must end with db #ff.
byte 1 = speed+hihat or pattern end marker (#ff)
Speed can be #04..#fc, must be a multiple of 2. Add 1 to the value to trigger the hihat.
byte 2 - instrument ch1
Valid values are #00 (silence), #01-#10. Add #80 to the value for pitch slide down,
or #c0 for pitch slide up. See also byte 4. Examples:
Hard kick: db #xx,#81,#08,#00,#10
Slide up: db #xx,#c1,#10,#c0,#20
byte 3 - note counter value ch1.
Valid values are #00-#ff. Values are inverse, ie. higher value means lower tone.
byte 4 - instrument ch2
Valid values are #00 (silence), #01-#10. You can add #80/#c0 as an auxiliary parameter for
a pitch slide present on ch1.
byte 5 - note counter value ch2
Same as byte 3.
rawp Sample Data Format
==========================
If you feel adventurous, you can add your own samples to sampledata.asm, or change the existing
ones. Samples must be 256 bytes long, and may only consist of values #00 and #10 (unless you
want funky colors to appear in the border area). The player reads chunks of 4 sample bytes and
combines them into one volume level.
Trivia
======
rawp stands for "Reasonably Accurate Waveform Playback".
********************************************************************************
SQUEEKER PLUS
by utz 07'2016 * www.irrlichtproject.de
********************************************************************************
ABOUT
=====
Squeeker Plus is a 1-bit/beeper engine for the Sinclair ZX Spectrum. It is based
on an original concept developed by zilogat0r for his Squeeker beeper engine.
FEATURES
========
- 4 tone channels, mixed PFM/PWM synthesis
- 2 interrupting click drums
- per-tick duty cycle envelopes
- channels 1 and 2 can play fixed-pitch noise instead of square waves
- channel 4 can use a fast pitch slide for drum simulation
- mixing at approx. 9511 Hz.
REQUIREMENTS
============
The following tools are required to use the xm2octode2k16 utility
- an XM tracker, for example Milkytracker (http://milkytracker.org) or OpenMPT
(http://openmpt.org)
- pasmo or a compatible Z80 assembler (http://pasmo.speccy.org)
pasmo must be installed in your search path, or must reside within the
squeekerplus folder.
COMPOSING MUSIC
===============
You can use the included XM template to compose music for Squeeker Plus.
However, this will only give a very rough approximation of how the music will
sound on an actual ZX Spectrum, even more so since not all of the engine's
features can be simulated properly in the template. Also, Squeeker Plus has
The following restrictions apply:
- The number of channels is fixed.
- The BPM value is fixed. The Speed value can be changed, however.
- Only the provided samples may be used; instruments can be cloned however (see
below).
- All other effects are ignored, except for the following:
Bxx - set loop point
E5x - set detune (only effective for the current note, ignored if set without
a note trigger)
Fxx - set Speed (= number of ticks per row, xx <= $1f). It is reset to the
global value at the beginning of a new pattern.
- Click drums should be used in channel 5/6. Only one click drum can be active
on a given pattern row.
- Click drums and the noise instrument have their pitch fixed at C-4.
A duty cycle envelope can be applied to tone, noise, and pitch slide
instruments. This can be done in two ways:
1) By setting a value in the volume column ($40 is assumed if no value is set).
2) By enabling the volume envelope in the instrument settings. This method will
override setting the duty via the pattern volume column. Envelope looping and
sustain are not supported.
Note that running all channels with high duty cycle values will cause the engine
to overload, effectively decreasing overall sound quality.
Very low duty cycle settings may mute the current note. The actual threshold at
which dropouts will occur depends on the note frequency.
In order to use multiple duty cycle envelopes, you will want to clone the
provided sample instruments. To do so, simply load one of the provided .xi
instruments into a free instrument slot. You may rename cloned instruments, but
you may not change the sample data.
The click drums cannot be cloned, and must remain in slots 1 and 2.
CONVERTING
==========
Running one of the provided compile scripts will convert your .xm file into
a .tap file that you can then load on a ZX Spectrum or an emulator.
compile.sh/.cmd will accept the following optional parameters, in this exact
order:
-t "song title"
-c "composer name"
-a address*
Example: compile.cmd -t "My Song" -c "Great Musician"
This will create a BASIC screen which reads "My Song by Great Musician".
Alternatively, you can use interactive-compile.cmd/.sh to interactively set
these parameters.
*The compile address will default to 32768 ($8000), but can be set to any other
location in uncontended RAM.
MUSIC DATA
==========
The music data for Squeeker Plus is split in three sections: Sequence, patterns,
and duty cycle envelopes.
The sequence section must come first. It consists of a list of pointers to the
patterns, in the order in which they are meant to be played. The list must be
terminated with a 0-word. Also, a label named "loop" must be present; this
specifies the location the player will loop to once it has completed the
sequence. The shortest possible sequence section is thus:
loop
dw pattern0
dw 0
After the sequence section, patterns and duty cycle sections will follow in
arbitrary order (even mixing the two is possible).
Patterns consist of one or more rows of note data. The rows are constructed as
follows:
1) speed + control byte A
The speed is given as (ticks*256). Set bits in the control byte have the
following effect:
bit 0 - skip freq/env reload for ch1
bit 2 - skip freq/env reload for ch2
bit 6 - end of pattern
bit 7 - skip freq/env reload for ch3
On the first row of a pattern, control byte A is always 0, ie. all channel
frequencies and envelope pointers must be set.
2) noise enable control ch1/2
The high byte sets noise for ch1, the low byte sets noise for ch2. $cb to enable
noise, $00 to disable it.
3) frequency ch1
4) envelope pointer ch1
5) freq ch2
6) env ch2
7) freq ch3
8) env ch3
9) control byte B
The high byte is always 0. the bits in the low byte have the following effect:
bit 0 - enable pitch slide ch4
bit 2 - trigger click drum 1 (kick)
bit 6 - skip freq/env reload for ch4
bit 7 - trigger click drum 2 (hihat)
10) freq ch4
11) env ch4
Each entry is one word long. Entries 1, 2, and 9 are mandatory, the rest is
optional, their presence depending on the control bytes. If control byte A is
$40, no further data follows for this pattern.
Duty-cylce envelopes consist of one or more single-byte entries with values
between $00 and $40. They must be terminated with a $80 byte. The shortest valid
envelope is thus
env1
db $40,$80
********************************************************************************
Tritone FX
by utz 09'2015
original Tritone code by Shiru 03'2011
********************************************************************************
About
*****
Tritone FX is a rewrite of the Tritone routine by Shiru. Like in the original,
there are 3 tone channels with variable duty cycle. However, Tritone FX adds a
few twists.
Things added:
- Effects tables: Tritone FX can change pitch, duty, and note lengths on the fly
during note playback, using table-based fx execution. With this, it is no
longer necessary to use the player at hypersonic speeds to achieve some of the
effects heard in more advanced Tritone tracks, for example by Strobe or
brightentayle.
- Noise. Channel 1 can be used to output noise instead of tone. Toggeling the
output mode of ch1 can be done via an fx command, so you can combine noise and
tone in one note.
- Per-row tempo control: The song tempo can be set at any time.
Things changed:
- Channel volume difference is less pronounced than in the original Tritone. The
loudest channel is ch2 (40%), followed by ch3 (32%), followed by ch1 (28%).
- Data format is changed completely, so original Tritone songs will not be
compatible.
Things removed:
- Click drums. Removed because they would create too much bloat in the song
data. I believe they are no longer needed, given the added functionality.
Unfortunately there is currently no editor available for this routine, and it
would be too complex to simulate via an XM template. So, for the time being, the
only option is to code the music by hand, in asm.
Music Data Format
*****************
Tritone FX music consists of 3 sections: The song sequence, the pattern data,
and the effect tables. The song sequence must come first. Pattern data and
effects tables can be located anywhere except at the start, the two can even be
mixed.
The song sequence contains the order in which the patterns are to be played. It
is terminated with a 0-word.
After the player has completed the sequence, it will loop back to the position
specified by the mandatory "loop" label. The shortest legal song sequence would
therefore be:
loop
dw pattern01
dw 0
To disable looping, uncomment line 36 in main.asm.
Pattern data consists of 6 words per row, which are as follows
offset function
(words)
+0 tempo*256 + noise flag (#8000 = noise enabled, 0 = noise disabled)
+ duty_ch1
+1 duty_ch2*256 + duty_ch3
+2 base frequency ch3
+3 base frequency ch2
+4 base frequency ch1
+6 fx table pointer
Patterns must be terminated with a 0-byte.
Effects tables can be any length, but the maximum number of steps that are
executed is determined by the current tempo setting (= number of ticks).
See the following section for details on how to design effects tables.
Effects
*******
Effects are triggered once every 256 sound loop iterations. This is a rather
fast rate - for a typical arpeggio, you'd need to set a new frequency once
every 3-4 rows in the fx table.
Effects take 0-3 word length arguments. The following effects are available:
fxNone
No effect will be executed on the current tick.
fxStop
Stop the fx table execution for this note.
fxJump,<label>
Jump to an arbitrary label on any fx table. Can be used to loop fx by
jumping backwards in the current table.
fxSetFCh1,<frequency>
fxSetFCh2,<frequency>
fxSetFCh3,<frequency>
Set the frequency of the given channel to the value given as argument.
fxSetFCh12,<frequency1>,<frequency2>
fxSetFCh13,<frequency1>,<frequency3>
fxSetFCh23,<frequency2>,<frequency3>
Set the frequencies of the given channel pair to the values given as args.
fxSetFCh123,<frequency1>,<frequency2>,<frequency3>
Set the frequencies of all 3 channels to the given values.
fxSetFChxxxCont,<frequencyx>,(...),<next effect>(,<args>,...)
Same as above, then execute another effect given as argument.
fxSetDCh1,<duty*256>
fxSetDCh2,<duty*256>
fxSetDCh3,<duty*256>
Set the wave duty of the given channel to the given value. The high byte of
this word determines the duty, the low byte is always 0.
fxSetDCh12,<duty1*256+duty2>
fxSetDCh13,<duty1*256+duty3>
fxSetDCh23,<duty2*256+duty3>
Set the wave duties of the given channel pair to the given values.
fxSetDch123,<duty1*256+duty2>,<duty3*256>
Set the wave duties of all channels to the given values. The low byte of
the second argument is always 0.
fxStopNoise
Disable noise mode, and mute channel 1.
fxStopNoiseCont,<next effect>(,<args>,...)
Disable noise, and execute another effect given as argument.
fxStopNoiseSetFCh1,<frequency>
Disable noise mode, and set the frequency of channel 1 to the give value.
fxStartNoiseSetFCh1,<frequency>
Enable noise mode, and set the frequency of channel 1 to the give value.
fxStartNoiseSetFCh1Cont,<frequency>,<next effect>(,<args>,...)
Enable noise mode, set the frequency of channel 1 to the give value, and
execute another effect given as argument.
fxCutCh1
fxCutCh2
fxCutCh3
Cut the note of the given channel. Same effect as setting the given
channel's frequency to 0, but also resets the channel's counter.
An example fx table for a looping octave arpeggio:
fxtab01
dw fxNone
t1lp
dw fxNone
dw fxNone
dw fxSetFCh1,#400
dw fxNone
dw fxNone
dw fxNone
dw fxSetFCh1,#800
dw fxNone
dw fxNone
dw fxNone
dw fxSetFCh1,#1000
dw fxNone
dw fxNone
dw fxNone
dw fxSetFCh1,#200
dw fxJump,t1lp
Hints
*****
In theory, an infinite number of effects can be chained by using the
xxxCont effect commands. However, this will lead to slowdowns if
(ab)used too much.
You can control the volume and sound of the noise with the Ch1 duty
setting.
VIBRA
by utz 07'2017 * irrlichtproject.de
********************************************************************************
About
=====
Vibra is a ZX Spectrum beeper music engine with two tone channels and a
dedicated noise channel. The tone channels support customizable vibrato and
slide effects. The vibrato effect has 7 speed settings, and 255 depth levels.
Effective vibrato speed depends on the note frequency used. Tone channels are
unbalanced, that means the second channel will play at approx. 80% volume of the
first channel.
The noise channel supports 255 pitch levels, and 127 volume levels. Noise
generator is only updated if there is enough free CPU time, so data reads etc.
may affect the noise timbre.
The usual interrupting click drums are absent from this engine, as the available
effects should be sufficient to create drum sounds.
The engine reloads song data on the fly during playback, thus mitigating the
common problem of row transition noises for the most part.
Technical details:
- 12-bit note frequency dividers
- 8-bit noise pitch dividers
- 7-bit noise volume
- 3-bit vibrato speed (relative to note frequency)
- 8-bit vibrato depth
- 8-bit slide speed
- mixing at 7812.5 Hz
Composing Music
===============
At the time of writing, there is no dedicated editor/converter for the engine,
so the only possibility is to write music directly in assembly data statements.
Configurable Parameters
=======================
Looping can be configured by defining "looping" as either 1 or 0 in main.asm. If
defined as 1, the player will loop back to the specified loop point once the
song sequence is completed. If defined as 0, the player will exit to BASIC at
the end of the song.
Data Format
===========
Music data for Vibra follows the usual approach: a sequence (order list) is
followed by one or more patterns.
The sequence contains a list of word-length pointers to the actual patterns, in
the order in which they are to be played. The list must be terminated by a
0-word. If looping is enabled (see above), a loop point must be specified
somewhere in the sequence by setting the "mloop" label. The shortest valid
sequence is thus:
mloop
dw ptn0
dw 0
The sequence is followed by one or more patterns, containing the actual note and
effects data. The music data consists of a mandatory control word, followed by
1-5 optional data words. The data is laid out as follows:
word bits function
--------------------------------------------------------------------------------
0 control word
0 if set, skip channel 1 update
2 if set, skip ch2 update
6 pattern end marker, see below
7 if set, skip noise channel update
8..13 speed (row length)
14..15 unused (must always be reset)
1 frequency divider ch1
0..11 divider
15 if set, skip ch1 fx update
2 fx settings ch1
0..7 vibrato depth or slide speed
Slides will wrap around unless the frequency divider used is a
multiple of the slide speed given.
8..15 fx type: 0 = slide down, 0x80 = slide up, other values = vibrato
8..14 vibrato speed (higher = slower).
ATTN: Only the highest set bit is evaluated. If bit 14 is set,
bit 8..13 must be reset (engine will crash otherwise).
3..4 same as word 1..2, but for ch2
5 0..6 noise volume (threshold)
8..11 noise pitch
Bits not mentioned above are ignored.
Patterns must be terminated with "dw #0040". Optional fields are never required,
however you may still wish to set them on the first row of the first pattern in
the sequence.
********************************************************************************
wtbeep v0.1 - 3 channel beeper engine
by utz 11'2016 * www.irrlichtproject.de
********************************************************************************
About
=====
wtbeep is an experimental 3-channel beeper engine for the ZX Spectrum. It offers
a set of 32 different "waveforms" to chose from. Also included are two click
drums with configurable parameters.
Composing Music
===============
Currently, no editor exists for wtbeep, so any music must be hand-crafted as
assembly data. See the following section on how to construct the necessary
music.asm files.
Waveforms
=========
The following waveforms are available:
#00 50% square
#01 32% square
#02 25% square
#03 19% square
#04 12.5% square
#05 6.25% square
#06 duty sweep (fast)
#07 duty sweep (slow)
#08 duty sweep (very slow)
#09 duty sweep (very slow, inverted start duty)
#0a duty sweep (slow) +octave
#0b duty sweep (slow) -octave
#0c duty sweep (fast) -octave
#0d vowel 1
#0e vowel 2
#0f vowel 3
#10 vowel 4
#11 vowel 5
#12 vowel 6
#13 rasp 1
#14 rasp 2
#15 phat rasp
#16 phat 2
#17 phat 3
#18 phat 4
#19 phat 5
#1a phat 6
#1b phat 7
#1c noise 1
#1d noise 2
#1e noise 3
#1f noise 4
Waveforms #13..#16 and #19..#1b play 2 octaves lower, the lowest octaves are
pretty much useless in these cases.
Data Format
===========
Music data for wtbeep follows the usual sequence-pattern approach.
The sequence contains one or more pointers to patterns, in the order in which
they are to be played. A label named "mLoop" must be present in the sequence to
determine the position the player will loop to after it has completed the
sequence. (To disable looping, uncomment lines 30-31 in main.asm.) The sequence
must be terminated with a 0-byte. The shortest legal sequence is thus:
mLoop
dw pattern
dw 0
Patterns contain the actual musical score. wtbeep uses a rather compact scheme
to encode pattern data.
word bit function
==========================================================================
0 * tempo*256|flags
0 skip update ch1
2 skip update ch2
6 end of pattern (see below)
7 skip update ch3
8..15 tempo (row length as number of ticks/frames)
1 * freq_div1|waveform1 (omitted when word 0, bit 0 set)
0..10 frequency divider ch1
11..15 waveform ch1
2 * as above, but for ch2 (omitted when word 0, bit 2 set)
3 * as above, but for ch3 (omitted when word 0, bit 3 set)
4 * click drum
Only one drum trigger can be used per row.
If no drum trigger is used, the high byte is omitted and only a
0-byte is written.
0 trigger kick
2 reset sweep counters
6 trigger hihat
8..15 click drum parameters
for kick, bit 8..15 = initial pitch (higher value = higher pitch)
for noise, bit 8 sets type (lower pitch if set), bit 9..15 sets
volume (higher value = louder)
The first pattern in the sequence must set all parameters.
Word 1 must be set at the start of each pattern.
Each pattern must end with a pattern end flag (#40).
For further information, refer to the example music.asm file, and the equates.h
file.
dw #100, #10F, #11F, #130, #143, #156, #16A, #180, #196, #1AF, #1C8, #1E3
dw #200, #21E, #23F, #261, #285, #2AB, #2D4, #2FF, #32D, #35D, #390, #3C7
dw #400, #43D, #47D, #4C2, #50A, #557, #5A8, #5FE, #65A, #6BA, #721, #78D
dw #800, #87A, #8FB, #984, #A14, #AAE, #B50, #BFD, #CB3, #D74, #E41, #F1A
dw #1000, #10F4, #11F6, #1307, #1429, #155C, #16A1, #17F9, #1966, #1AE9, #1C82, #1E34
dw #2000, #21E7, #23EB, #260E, #2851, #2AB7, #2D41, #2FF2, #32CC, #35D1, #3905, #3C68
dw #4000, #43CE, #47D6, #4C1C, #50A3, #556E, #5A83, #5FE4, #6598, #6BA3, #7209, #78D1
dw #8000, #879D, #8FAD, #9838, #A145, #AADC, #B505, #BFC9, #CB30, #D745, #E412, #F1A2********************************************************************************
wtfx - wavetable player with fx
by utz 02'2016 * www.irrlichtproject.de
********************************************************************************
==================================== ABOUT =====================================
wtfx is a two-channel beeper with almost distortion-free wavetable playback. It
can be used to create complex sound effects, thanks to it's table-based fx
system. The sound is mixed at 17.5 KHz, and there are 4 volume levels per
channel. Channel volumes are asynchronous, with channel 2 being slightly louder
than channel 1. Tempo can be controlled per step.
The player is provided in source format only, to be assembled with pasmo.
================================== COMPOSING ===================================
There is currently no editor available for this player, and it is too complex to
simulate via an XM template. So unfortunately the only possibility to make music
with it is by hand-coding all the data in asm. For reference, an example note
table has been included.
You can also configure a few things in main.asm. To disable looping, uncomment
line 41. If you want more fine-grained speed control, replace both nops in line
116 and 117 with "dec b". If you don't want to use any effects, comment out
lines 85, 282-290, and 295-491, and omit the fx pointers in the pattern data.
================================== WAVETABLES ==================================
All used wavetables must be linked in 'samples.asm'. The wavetables themselves
must be exactly 256 bytes long, and may only use the following values:
0x00 - silence
0x88 - 25% volume
0xcc - 50% volume
0xee - 75% volume
0xff - 100% volume
More complex waveforms may fail to play properly.
See /samples for some examples.
You can also create wavetables with the included wav2smp.pl utility, using
headerless unsigned 8-bit wav samples as input. The syntax is as follows:
wav2smp.pl <volume> <infile> [<outfile>]
where volume is a value between 1 and 4.
============================== MUSIC DATA FORMAT ===============================
wtfx music data is split into three sections: song sequence, patterns, and fx
tables.
The song sequence must come first in music.asm. It consists of a list of
pointers to patterns, according to the order in which they are to be played. It
must contain a label named "loop", the position of which defines the loop point
to which the player will jump after it has finished playing the song. The song
sequence is terminated with 0x0000. The shortest possible sequence is therefore
loop
dw pattern0
dw 0
After the song sequence, there should be one or more patterns of note data.
These are organized in rows of 6 words. The order is as follows:
1. tempo * 256 + flags (always 0, reserved for further use)
2. 16-bit note value channel 1
3. pointer to wavetable channel 1
4. 16-bit note value channel 2
5. pointer to wavetable channel 2
6. pointer to fx table
Patterns must be terminated with 0x40.
Last but not least, some fx tables are needed. These consist of one or more
commands, which are in turn followed by 0-4 word or byte length arguments.
The following commands are available:
command arguments function
tExecNone none do not execute any fx on this row
tExecStop none stop wavetable execution for this row
tExecLoop loop pointer jump to an arbitrary point in the current
or another fx table. Additionally, execute
the next command at the loop point.
tf1 note value ch1 change note of ch1 to the given value
tf1s1 note value ch1, change ch1 note and wavetable to the given
hi-byte of wavetab ch1 values
tf1s1f2 note value ch1, change both notes and wavetable ch1 to the
hi-byte of wavetab ch1, given values
note value ch2
tf1s1s2 note value ch1, change note value ch1 and both wavetables
hi-byte of wavetab ch1,
hi-byte of wavetab ch2
tf1f2 note value ch1, change both note values
note value ch2
tf1f2s2 note value ch1, change both note values and wavetable ch2
note value ch2,
hi-byte of wavetab ch2
tf1s2 note value ch1, change ch1 note and ch2 wavetable to the
hi-byte of wavetab ch2 given values
tf1s1f2s2 note value ch1, change all notes and wavetables pointers
note value ch2, to the given values
hi-byte of wavetab ch1, ATTN: order of arguments is changed here!
hi-byte of wavetab ch2
ts1 hi-byte of wavetab ch1 change wavetable ch1 to the given value
ts1f2 hi-byte of wavetab ch1, change wavetable ch1 and note value ch2 to
note value ch2 the given values
ts1f2s2 note value ch2, change both wavetable pointers and the
hi-byte of wavetab ch1, note value of ch2
hi-byte of wavetab ch2 ATTN: order of arguments is changed here!
ts1s2 hi-byte of wavetab ch1, change both wavetable pointers
hi-byte of wavetab ch2
tf2 note value ch2 change note of ch2 to the given value
tf2s2 note value ch2, change ch2 note and wavetable to the given
hi-byte of wavetab ch2 values
ts2 hi-byte of wavetab ch2 change wavetable ch2 to the given value
The order in which the patterns and fx tables are provided has no importance.
See 'music.asm' for more details.
================================================================================
********************************************************************************
xtone beeper routine for ZX Spectrum
by utz 09'2015
********************************************************************************
Features
********
- 6 channels with square wave sound (sort of)
- 16-bit frequency precision
- variable duty cycle
- per-step speed control
- 3 interrupting click drums
Requirements
************
The following tools are required to use the xm2xtone utility
- an XM tracker, for example Milkytracker (http://milkytracker.org)
- pasmo or a compatible Z80 assembler (http://pasmo.speccy.org)
- Perl (http://www.perl.org/get.html)
pasmo and Perl must be installed in your search path, or must reside within the
xtone folder.
Composing Music
***************
You can compose music for the xtone player using the XM template that comes
bundled with xtone. However, this will only give a very rough estimate of how
the music will sound on an actual ZX Spectrum.
When using the XM template, consider the following:
- You may not change the number of channels.
- Notes must be in channel 1-6.
- Drums must be in channel 7-8, and you cannot set more than one per row.
- Changes to the BPM value or to the instruments have no effect.
- You may change the speed value globally, or at any point by using command Fxx,
where xx must be in the range of 0-$1f.
- The note range is limited from C-0 to B-5.
- You may set note detune with command E5x.
- All other effect commands, as well as volume settings will be ignored.
When you're done composing, simply run the provided compile.bat (Win) resp.
compile.sh scripts to generate a .tap file of your music. If you only want to
generate the music data, run xm2xtone.pl without any arguments.
Data Format
***********
xtone music data consists of a song sequence, followed by the pattern data. The
song sequence is a list of pointers to the actual note patterns, in the order in
which they are played. The sequence is terminated by a 0-word. At some point in
the sequence you must specify the label "loop", which is where the player will
jump to after it has completed the sequence. The shortest possible sequence would
thus be:
loop
dw ptn00
dw 0
Following this are the note patterns. Each row in the patterns consists of 9
words (18 bytes).
word 1: speed * 256 + drum triggers (1 = kick, 5 = snare, $81 = hihat)
word 2: duty ch1 * 256 + duty ch2 * 16 + duty ch3 + duty ch4/16
word 3: duty ch5 * 256 + duty ch6
word 4: frequency ch1
word 5: frequency ch2
word 6: frequency ch3
word 7: frequency ch4
word 8: frequency ch5
word 9: frequency ch6
In order to mute a channel, simply set the frequency to 0.
Note patterns are terminated with a single $40 byte.
********************************************************************************
yawp (Yet Another Wave Player)
by utz 09'2015
********************************************************************************
Features
********
- 3 channel PCM WAV playback
- 2 bit sample depth
- 5 octaves note range
- 16-bit frequency resolution
- per-row speed control
- 16.2 KHz mixing
Requirements
************
The following tools are required to use the xm2yawp utility
- an XM tracker, for example Milkytracker (http://milkytracker.org)
- pasmo or a compatible Z80 assembler (http://pasmo.speccy.org)
- Perl (http://www.perl.org/get.html)
pasmo and Perl must be installed in your search path, or must reside within the
yawp folder.
Composing Music
***************
You can compose music for the yawp player using the XM template that comes
bundled with yawp. However, this will only give a very rough estimate of how
the music will sound on an actual ZX Spectrum.
When using the XM template, consider the following:
- You may not change the number of channels.
- Notes must be in channel 1-3.
- Changes to the BPM value or to the instruments have no effect.
- You may change the speed value globally, or at any point by using command Fxx,
where xx must be in the range of 0-$1f.
- The note range is limited from C-0 to B-4.
- You may set note detune with command E5x.
- All other effect commands, as well as volume settings will be ignored.
By default, yawp modules loop back to the start. You can change this
manually by moving the "loop" label in music.asm to another position in the
sequence. To disable looping entirely, uncomment line 47 in main.asm.
When you're done composing, simply run the provided compile.bat (Win) resp.
compile.sh scripts to generate a .tap file of your music. If you only want to
generate the music data, run xm2yawp.pl without any arguments.
Adding New Samples to the Converter
***********************************
There is no easy way of doing this, unfortunately. The procedure is as follows:
Step 1: Make a sample in qaop's native format (see next section for details)
Step 2: Append the sample to the @instruments array in xm2yawp.pl (near the end)
Step 3: Sample a C-4 note, add it to the XM template as a new instrument, and
activate sample looping.
yawp Sample Data Format
***********************
yawp lets you use your own samples, or rather looped waveforms. Samples must be included in
samples.asm. Check out the /samples folder for inspiration.
yawp samples have a fixed length of 256 bytes. The format is unsigned PCM, meaning all bytes
in the sample denote a relative volume. Sample byte volumes are defined as follows:
#00 - silence
#10 - 33% volume
#30 - 66% volume
#70 - 100% volume
Other values are not permitted.
You can use the included wav2smp.pl script to convert unsigned raw (header-less) 8-bit PCM WAV
files to yawp .smp format.
Data Format
***********
The music data consists of an order list containing the sequence of patterns, and the pattern
data itself. The order list must be ended with a 0-word and must include a "loop" label
somewhere. The shortest legal sequence is thus:
loop
dw ptn01
dw 0
Layout of the rows in pattern data is as follows:
offset length function
[+0 byte #00 = end marker]
+0 word [hi-byte of sample pointer ch3]*256 + speed
+2 word frequency ch1
+4 word frequency ch2
+6 word frequency ch3
+6 word [hi-byte of sample pointer ch1*256] + [hi-byte of sample pointer ch2]
Patterns must end with a 0-byte.********************************************************************************
zbmod beeper routine for ZX Spectrum
by utz 06'2016
********************************************************************************
About
=====
zbmod is a simple mod player for the ZX Spectrum beeper. It mixes 3 channels of
PCM WAV samples in realtime, at a rate of approximately 9.1 KHz.
zbmod comes in two different flavours - for NMOS and CMOS Z80 CPUs. Original
ZX models use an NMOS CPU, most clones use a CMOS CPU. It's easy to tell which
CPU your Spectrum is sporting - if you get no sound and/or white stripes in the
border area with the NMOS version, you've got a CMOS CPU.
The NMOS/CMOS versions do not work properly on emulators, they will produce a
high-pitched parasite tone. Hence, a special emulator version has been included,
which will counter-act this problem to some extend.
Requirements
============
The following tools are required to use the xm2octode2k16 utility
- an XM tracker, for example Milkytracker (http://milkytracker.org) or OpenMPT
(http://openmpt.org)
- pasmo or a compatible Z80 assembler (http://pasmo.speccy.org)
pasmo must be installed in your search path, or must reside within the
zbmod folder.
Composing Music
===============
You can compose music for the zbmod player by converting ordinary 4-channel
XMs with the included xm2zbmod utility. For reference, a demo XM has been
included.
Any XM fed into xm2zbmod will be subject to these restrictions:
- The XM must have exactly 4 channels.
- Any data in the 4th channel is ignored.
- The note range is limited. The exact range available changes depending on
the type of sample used. Notes from C-1 to C-3 will generally be available,
notes from C-0 - B-3 and/or C#3 - B#4 may or may not be available. The
converter will report offending notes when encountered. Running xm2zbmod with
the -r flag will print the available note ranges of all samples currently in
use.
- The relative note offset for all samples must be C-4 (+0) or higher.
- Notes in the lowest octaves may be detuned.
- Ping-pong and one-shot sample looping are not supported.
- Multi-sample instruments are not supported.
- The amount of samples you can use is restricted by the Spectrum's memory. A
warning will be issued either by the converter or the assembler if the limit
has been exceeded. Normally, you should get away with around 100 KB of sample
data.
- Instrument settings are ignored.
- All notes will be cut at the end of a pattern.
- The global BPM must be set to 86, and cannot be changed.
- You may change the speed value globally, or at any point by using command Fxx,
where xx must be in the range of 0-$1f.
- You may set note detune with command E5x.
- You may set the sequence loop point with command Bxx.
- All other effect commands, including volume settings will be ignored.
- The resulting sound quality will of course be much, much lower.
By default, zbmod will loop until a key is pressed. To disable looping,
uncomment line 57 in main.asm.
When you're done with composing, simply run the provided compile.cmd resp.
compile.sh scripts to convert your XM file into ZX Spectrum .tap files (see the
"About" section for details on the different output files).
compile.cmd/.sh will accept the following optional parameters (in the exact
order listed here):
-t "song title"
-c "composer name"
-a address
Example: compile.cmd -t "My Song" -c "Great Musician"
This will create a BASIC screen which reads "My Song by Great Musician".
Alternatively, you can use interactive-compile.cmd/.sh to interactively set
these parameters.
HINT 1: If you get a lot of noise between rows, you can manually adjust the
nextFrame pointers in the sample data. These normally point to "core0". Increase
the value after "core" until the noise is reduced. The maximum is "core21".
HINT 2: It is usually a good idea to send your samples through a low-pass filter
with a cutoff of around 4400 Hz, because any frequency above this threshold will
produce aliasing sounds in zbmod.
Data Format
===========
SAMPLE DATA
Sample data is maintained in two files, "samples.asm" and "sampletab.asm".
"samples.asm" contains the actual sample data. It starts with an obligatory
entry that looks like this:
smp0 db 1,0
After this, an arbitrary number of PCM samples may follow. Each sample should
be prefixed by a label, and end with a 0-byte. The actual sample data is
unsigned and may contain values from 1 (lowest relative volume - not 0!) to 8
(highest relative volume).
"sampletab.asm" contains a list of pointers to the samples in "samples.asm".
There are two list entries for every sample. The first is the sample loop point-
if you don't want the sample to loop set this value to "smp0". The second value
is the actual pointer to the start of the sample, ie. the label you used in
"samples.asm". The first line in the sample table must be
dw smp0,smp0
This is the "silent sample", you use this to mute a channel.
MUSIC DATA
zbmod music data consists of a song sequence, followed by one or more patterns.
The song sequence is a list of pointers to the patterns, in the order in which
they are to be played. The sequence must contain the label "loop" somewhere,
this is where the player will loop to once it has finished the sequence. The
sequence list must be terminated with a 0-word. The shortest possible sequence
thus looks like this:
loop ;loop point
dw ptn00 ;pointer to pattern 0
dw 0 ;end marker
Patterns consist of one or more rows of note and instrument data. The layout is
as follows:
First byte is the flag byte. Flags are
bit 0 - data for channels 3 is omitted
bit 2 - data for channels 2 is omitted
bit 6 - data for channels 1 is omitted
bit 7 - pattern end
The second byte is the row length in ticks.
If bit 6 of the flag byte is cleared, the next byte sets the sample for channel
1. It is an 8-bit pointer to an entry in the sample table (sampletab.asm). Thus,
to use sample 1, you would set this byte to 4 (because each entry is 4 bytes and
the silent sample is the first entry in the table). This is followed by an 8-bit
frequency counter value.
If bit 2 of the flag byte is cleared, data for channel 2 follows. This works the
same as for channel 1.
If bit 0 of the flag byte is cleared, data for channel 3 follows. This works
like with the other channels, but after the sample and frequency bytes you must
add a data word pointing directly to the desired sample (not to the table).
All pattern rows are terminated by a word-length pointer to next core to be
executed in the player. This sets the initial relative volume for this row. It
is often sufficient to set this to "core0" (ie. starting volume = 0), however
for cleaner sound you might want to point to another of zbmod's 22 cores.
Note: On the first row of each pattern, you must set the data for all channels
(ie. flag must be 0). Also, each pattern must be terminated with a stand-alone
flag byte set to 0x80.Ðа памÑÑÑ Ð¼Ð¾Ð³Ñ ÑказаÑÑ, ÑÑо Ñ ÑобиÑал ÐовоÑибиÑÑкий ваÑÐ¸Ð°Ð½Ñ (пеÑаÑнÑе плаÑÑ Ð¸Ð·Ð³Ð¾ÑавливалиÑÑ Ð½ÐµÐ»ÐµÐ³Ð°Ð»Ñно на ÐÑаÑноÑÑÑком заводе ÑелевизоÑов). Те плаÑÑ, коÑоÑÑе Ñ Ð¿ÑиобÑел бÑли изгоÑÐ¾Ð²Ð»ÐµÐ½Ñ Ð² 1989 годÑ. ÐÑе Ñ Ð¼ÐµÐ½Ñ ÑеÑез неÑколÑко Ð»ÐµÑ Ð¿Ð¾ÑвилÑÑ ÐºÐ¾Ð¼Ð¿ÑÑÑÐµÑ Ð¡ÐºÐ¾Ñпион 256 Ðб (плаÑÑ Ð¿ÑивознÑе). ÐÑпил на ÑадиоÑÑнке гоÑовÑй под диÑкеÑÑ. Также в Ñ
Ð¾Ð´Ñ Ð±Ñли плаÑÑ ÐенингÑад 48 и 128, ÐенÑагон, ÐÑоÑи. СобÑÑвенно ÐÑаÑноÑÑÑкий ваÑÐ¸Ð°Ð½Ñ Ð±Ñл ÐÑаÑмаÑевÑкий 48Рв меÑаллиÑеÑком ÑÑезеÑованном коÑпÑÑе пÑимеÑно 20Ñ
20Ñ
2 Ñм, окÑаÑеннÑй в ÑеÑÑй ÑÐ²ÐµÑ (кажеÑÑÑ Ð¼Ð¾Ð»Ð¾Ñковой ÑмалÑÑ). Ðго изгоÑавливал на заводе ÐÑаÑÐ¼Ð°Ñ Ð¸ пÑодавал СеÑгей ÐеÑÑов. У него же бÑла одна из ÑамÑÑ
болÑÑиÑ
коллекÑий ÐÐ Ð´Ð»Ñ Ð¡Ð¿ÐµÐºÑÑÑма. ÐÑÐ¾Ñ ÐºÐ»Ð¾Ð½ бÑл одним из пеÑвÑÑ
на ÑадиоÑÑнке ÐÑаÑноÑÑÑка, пÑакÑиÑеÑки одновÑеменно Ñ ÐовоÑибиÑÑким ваÑианÑом.
Ðозможно в моей коллекÑии в Ñазделе железа ÑÑо-Ñо из ÑÑиÑ
клонов можно найÑи, ÑейÑÐ°Ñ Ñже не помнÑ. ÐоиÑкал - не наÑел. Ðаже Ñвои ÐºÐ¾Ð¼Ð¿Ñ Ð½Ðµ ÑоÑал. ТолÑко ÑÑ
ÐµÐ¼Ñ ÐовоÑибиÑÑкого ваÑианÑа оÑÑнÑл - болÑÑÐ°Ñ Ð¿ÑоÑÑÑÐ½Ñ Ð½Ð° неÑколÑкиÑ
ÑоÑкаÑ
в коллекÑии.
Ð 1989 Ð³Ð¾Ð´Ñ 48Ð ÐÑаÑмаÑевÑкий Ñже пÑодавалÑÑ, Ñ.к. Ð¼Ñ Ð¾Ð´Ð¸Ð½ ÑкземплÑÑ Ð¿Ð¾ÐºÑпали Ð´Ð»Ñ Ð¿ÑоекÑа клиники глазника ФедоÑова.
ÐÑл Ñакой мини коопеÑаÑивÑик из ÑÑеÑ
Ñеловек.Ðо ÑколÑко он ÑÑоил Ñже не Ð¿Ð¾Ð¼Ð½Ñ Ð¸ ÐºÐ°ÐºÐ°Ñ ÑÑ
ема бÑла взÑÑа за оÑÐ½Ð¾Ð²Ñ Ð½Ðµ ÑкажÑ.
Свой СкоÑпион 256 кÑпил доволÑно поздно, когда во вÑÑ Ñже пÑодавалиÑÑ 128-е. Ðаже его ÑÐµÐ½Ñ Ð½Ðµ помнÑ.
ÐабоÑÑ Ð¼Ð¸ÐºÑоÑÑ
ем пÑивозили из ÐоÑÐºÐ²Ñ - ÑамолеÑÑ ÑÑда ÑаÑÑо леÑали. ÐлаÑÑ ÑкоÑее вÑего копиÑовалиÑÑ Ð½Ð° меÑÑнÑÑ
заводаÑ
.
ÐолÑÑÑÑ Ð¿Ð¾Ð¿ÑлÑÑноÑÑÑ Ð¿ÑиобÑели ÐенÑÐ°Ð³Ð¾Ð½Ñ 128, но Ñ ÐµÐ³Ð¾ Ñак и не кÑпил. ÐÑо-Ñо даже ÐÑоÑи 1024 ÑобиÑал.
Я из ÑÑой ÑÑ
ÐµÐ¼Ñ ÑобÑал ÑиÑÐ°Ð»ÐºÑ Ð´Ð»Ñ ÐºÐ°ÑÑÐµÑ - оÑÐµÐ½Ñ Ð½Ð°Ð´ÐµÐ¶Ð½Ð¾ ÑÑиÑÑвала. СеÑгей ÐеÑÑов ÑанÑÑе вÑеÑ
ÑÑел Ñо ÑпековÑкого ÑÑнка - занÑлÑÑ Ð¸Ð³ÑовÑми пÑиÑÑавками.
У него, пожалÑй, ÑамÑе болÑÑие маÑÑÑÐ°Ð±Ñ Ð±Ñли. Ðго Ñменил СÑÑпаков - ÑÑал возиÑÑ Ð½Ð°Ð±Ð¾ÑÑ Ð¼Ð¸ÐºÑоÑÑ
ем, заÑем гоÑовÑе СкоÑпионÑ. Я Ñ Ð½ÐµÐ³Ð¾ Ñвой ÑкоÑпион бÑал.
ÐÑоконÑÑлÑÑиÑоваÑÑÑÑ Ñже не Ñ ÐºÐ¾Ð³Ð¾ - Ñ Ð² дÑÑгом гоÑоде.
ÐÑаÑмаÑевÑкий 48РвнеÑне бÑл в алÑминиевом ÑÑезеÑованном коÑпÑÑе, покÑаÑенÑй ÑеÑой молоÑковой ÑмалÑÑ. Ð Ð°Ð·Ð¼ÐµÑ Ð¿ÑимеÑно 22Ñ
22Ñ
2 Ñм. Ðакой ваÑÐ¸Ð°Ð½Ñ Ð¿Ð»Ð°ÑÑ ÑÑоÑл внÑÑÑи не помнÑ. ÐаказÑвал его на заводе ÐÑаÑÐ¼Ð°Ñ Ð¡ÐµÑгей ÐеÑÑов. ÐÑо, пожалÑй, единÑÑвеннÑй Спекки, коÑоÑÑй на ÐºÐ¾Ð½ÐµÑ 80-Ñ
в гоÑовом виде изгоÑавливалÑÑ Ð¸ пÑодавалÑÑ Ð² ÐÑаÑноÑÑÑке заводÑким ÑпоÑобом.
РадиоÑÑнок в конÑе 80-Ñ
ÑÑиÑ
ийно оÑганизовалÑÑ Ð½ÐµÐ¿Ð¾Ð´Ð°Ð»ÐµÐºÑ Ð¾Ñ ÑиÑменного магазина "ÐелодиÑ", но вÑкоÑе из-за ÑÑÑоиÑелÑÑÑва дома Ñакже ÑÑиÑ
ийно пеÑееÑ
ал на аÑÑалÑÑиÑованнÑÑ Ð¿Ð»Ð¾ÑÐ°Ð´ÐºÑ Ð¿ÑÑмо пеÑед ÑпомÑнÑÑÑм магазином. Ðо заÑем ÑадиолÑбиÑелей и оÑÑÑда Ñогнали на плоÑÐ°Ð´ÐºÑ Ð·Ð° ÑиÑком. Рв конÑе конÑов еÑе далÑÑе за ÑиÑком бÑвÑÑÑ Ð°Ð²ÑÐ¾Ð±Ð°Ð·Ñ Ð¿ÐµÑеделали под ÑадиоÑÑнок, где он до ÑиÑ
Ð¿Ð¾Ñ Ð¸ ÑÑÑеÑÑвÑеÑ.
СоÑÑ Ð¿Ð¾Ð½Ð°ÑÐ°Ð»Ñ Ñ Ð¿ÑиобÑеÑал на ÑадиоÑÑнке, по Ñем вÑеменам его пÑодавал в оÑновном СеÑгей ÐеÑÑов. Ðо его ÑбоÑники не бÑли ÑемаÑиÑеÑкими. Ðогда Ñ Ð¼ÐµÐ½Ñ Ð½Ð°ÐºÐ¾Ð¿Ð¸Ð»Ð¾ÑÑ Ð½ÐµÐ¼Ð½Ð¾Ð³Ð¾ ÑоÑÑа и Ñ Ð¾ÑÑалÑÑ Ð±ÐµÐ· ÑабоÑÑ, Ñо ÑÑал ÑоÑÑавлÑÑÑ ÑемаÑиÑеÑкие ÑбоÑники ÑнаÑала на каÑÑеÑаÑ
, заÑем и на диÑкеÑаÑ
. ÐÑо пÑодолжалоÑÑ Ð¿ÑимеÑно Ñ 1990 года до 1 ÑнваÑÑ 2000 года. ÐоÑле Ñего занималÑÑ ÐºÐ¾Ð»Ð»ÐµÐºÑией ÑолÑко на CD, далее DVD. ФидоÑнÑе ÑбоÑники ÑоÑÑавлÑл (еле наÑел в ÑобÑÑвенной коллекÑии NZXS3701/SOFTWARE/DOS/TR-DOS/TRD/ZXFIDO) c 1997 по 2001 год. Там же в ÑоÑедниÑ
папкаÑ
еÑÑÑ ÑоÑки и обÑÐ°Ð·Ñ Ð´ÑÑгиÑ
ÑбоÑников, ÑоÑÑавленнÑÑ
мной.
ÐоммеÑÑеÑкий ÑоÑÑ. ÐвÑоÑÑ, конеÑно пÑÑалиÑÑ Ð¿ÑодаваÑÑ, но коммеÑÑеÑкого ÑпÑоÑа не бÑло. Ðне впоÑледÑÑвии давали Ð´Ð»Ñ ÑаÑпÑоÑÑÑанениÑ, ÑÑÐ¾Ð±Ñ Ñ
оÑÑ Ð¸Ð·Ð²ÐµÑÑноÑÑÑ Ð¿Ð¾Ð»ÑÑиÑÑ. Ðо 1997-1998 года? СкоÑее вÑего, вÑледÑÑвие ÑаÑпÑоÑÑÑÐ°Ð½ÐµÐ½Ð¸Ñ Ð±Ð¾Ð»ÑÑого колиÑеÑÑва инÑоÑмаÑии по пÑогÑаммиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð½Ð° Спекки, поÑвилоÑÑ Ð¼Ð¾Ð»Ð¾Ð´Ð¾Ðµ поколение пÑогÑаммиÑÑов, коÑоÑÑе и ÑÑали ÑоздаваÑÑ ÑоÑÑ Ð´Ð»Ñ Ð¡Ð¿ÐµÐºÐºÐ¸. СÑаÑÑе авÑоÑÑ, ÑкоÑее наобоÑоÑ, пиÑали болÑÑе Ð´Ð»Ñ ÑвоиÑ
нÑжд.
Ðемного ÑÑоÑнÑ. СеÑгей ÐеÑÑов коллекÑÐ¸Ñ ÑоÑÑа пÑивозил ÑкоÑее вÑего из ÐоÑквÑ. Тогда вÑÑ Ð¾ÑÑÑда везли. ÐоÑле Ñого как он ÑÑел Ñо ÑпековÑкого ÑÑнка вÑÑ ÐРдоÑÑалоÑÑ ÐлекÑандÑÑ Ð¡ÑÑпаковÑ, коÑоÑÑй к ÑÐ¾Ð¼Ñ Ð²Ñемени занималÑÑ Ð½Ð° ÑадиоÑÑнке ÑпековÑким железом (набоÑÑ Ð¿Ð»Ð°Ñа + деÑали), коÑоÑÑе он Ñоже ÑкоÑее вÑего возил из ÐоÑÐºÐ²Ñ Ð¸ ÐиÑеÑа. Ðо ÑÑ
Ð¾Ð´Ñ ÐлекÑандÑа ÑÑа коллекÑÐ¸Ñ Ð´Ð¾ÑÑалаÑÑ Ð¼Ð½Ðµ, Ñ
оÑÑ Ðº ÑÐ¾Ð¼Ñ Ð²Ñемени и Ñ Ð¼ÐµÐ½Ñ Ð±Ñло немало ÑпековÑкого ÐÐ. Я ÑобиÑал вÑе коллекÑии ÑпековÑкого ÑоÑÑа, коÑоÑÑе мне пÑиноÑили. Ðни вÑе ÑобÑÐ°Ð½Ñ Ð² моем ZX-аÑÑ
иве под именами или никами ÑеÑ
, кÑо пÑиноÑил иÑ
. ÐÑе диÑкеÑÑ Ð² коллекÑиÑÑ
оÑÑÐ°Ð²Ð»ÐµÐ½Ñ Ð±ÐµÐ· изменениÑ, за иÑклÑÑением Ñого, ÑÑо Ñ Ð¸Ñ
пеÑевел Ñ ÑеалÑнÑÑ
диÑÐºÐµÑ Ð² обÑÐ°Ð·Ñ TRD или TD0. Ðз кÑаÑноÑÑÑкиÑ
коллекÑий имеÑÑÑÑ:
ROWSAN - 152Mb (в TD0 и TDI);
VBV - 394Mb (Ð¼Ð¾Ñ ÐºÐ¾Ð»Ð»ÐµÐºÑÐ¸Ñ Ð´Ð¸ÑкеÑ, коллекÑÐ¸Ñ LSA-СеÑÐ³ÐµÑ Ðанкина; ÐеÑÑова СеÑгеÑ; СÑÑпакова ÐлекÑандÑа; Rowsan-Романова СеÑгеÑ; СÑаÑа; AVO-ÐндÑÐµÑ ÐвÑинникова - мÑзÑÐºÐ°Ð½Ñ Ð¿Ð¾Ð»Ð½Ð¾ÑÑÑÑ ÑаÑÑоÑÑиÑован в "ÐоÑÑалÑгиÑ");
ÐÑе ÑекламнÑй ÑиÑ, коÑоÑÑм Ñ Ð¿Ð¾Ð»ÑзовалÑÑ Ð½Ð° балке. ÐокÑÑл лаком Ð¾Ñ Ð´Ð¾Ð¶Ð´Ñ. ÐовÑе ÑбоÑники вÑкладÑвал в виде диÑÐºÐµÑ Ð¸ каÑÑÐµÑ Ð¾ÑделÑно. СÑоÑал Ñебе на памÑÑÑ, пока ÑовÑем не иÑпоÑÑилÑÑ.
Vladimir Bogdanovitch vbvzx@narod.ru
I remember that I assembled the Novosibirsk variant of Speccy (its PCBs were produced illegally at the Krasnoyarsk television factory). The boards I had bought were produced in 1989. After a few years, I acquired Scorpion 256 KB (with the boards shipped from outside). I bought one at the radio market, ready with the disk drive. There also were popular boards of Leningrad 48 and 128, Pentagon, Profi. The native Krasnoyarsk variant was a 48K made at Krasmash, in a metallic (aluminium?) milled case around 20õ20õ2 (or 22x22x2) cm, painted grey (maybe with enamel). I don't know what kind of scheme was inside. It was ordered for production at Krasmash and sold by Sergey Petrov. He also had one of largest Speccy software collections and the circulation. He quit the Spectrum market one of the first, when he switched to game consoles.
I don't remember if my collection contains these clones in the hardware section. I couldn't find now. I haven't even photographed my computers. I only photographed the scheme of Novosibirsk variant - a big sheet in several photos in the collection.
The Krasmash variant was possibly the only Speccy mass-produced in Krasnoyarsk in the 80's. This clone was one of the first at the Krasnoyarsk radio market, almost simultaneously with Novosibirsk variant. We bought one unit in 1989, for Fyodorov's eye clinic.
We had a small cooperative of three people. I don't remember the price.
I also don't remember the price of my Scorpion 256. By that time, there were a lot of 128K machines.
The chips were shipped from Moscow on planes. The boards were possibly copied in Krasnoyarsk.
Pentagon 128 was popular, but I haven't bought one. Somebody even assembled Profi 1024.
From the scheme, I assembled a tape reader that worked very well.
Alexander Stupakov was the biggest vendor after Sergey Petrov. He started to bring the chipsets, then complete Scorpions. I bought mine from him.
Now I can't ask anybody - I live in another city.
The radio market appeared in late 80's spontaneously, near the company store of "Melodia". When a house was to be built there, the radio market also spontaneously moved to the asphalt square just before the store. Then they drove the radio amateurs to the square behind the circus. And finally even farther, to the former motor depot, where the radio market still exists.
In the beginning, I bought software at the radio market, mostly from Sergey Petrov. However, his packs were not thematic. When I had enough software and no job, I started to make thematic sets on tapes, then on disks. This started approximately in 1990, and ended at the 1th January of 2000. After that, I concerned myself only with the CD collection, that later became DVD, then many DVDs. I made Fidonet collections (hard to find: NZXS3701/SOFTWARE/DOS/TR-DOS/TRD/ZXFIDO) from 1997 to 2001. Nearby directories contain photos and images of my other collections.
As for commercial software. The authors tried to sell software, but there was no commercial demand. They gave me software for spreading, just to be famous. Maybe until 1997 or 1998? Most likely, after 1998, because of more information available about Speccy programming, a new generation of programmers appeared that started to write Speccy software. The old authors mostly wrote for themselves.
To be more precise, Sergey Petrov seemed to bring software from Moscow. Everybody did then. When he quit, all his software went to Alexander Stupakov, who was engaged in Spectrum hardware for long time (DIY sets of PCB + chipset, that he most likely brought from Moscow and Saint-Petersburg). When Alexander quit, all this collection came to me, although I already had a lot of software. I collected all the Speccy software collections that people brought to me. All of them are located in my ZX archive under the names or nicknames of their authors or who brought them. All the disks in the collections are left unchanged, I only transferred them from real floppies to TRD or TD0 images. There are such collections from Krasnoyarsk:
ROWSAN - 152Mb (in TD0 and TDI);
VBV - 394Mb (my disk collection, collections of LSA-Sergey Lankin; Sergey Petrov; Alexander Stupakov; Rowsan-Sergey Romanov; Stas; AVO-Andrey Ovtchinnikov - the composer is fully sorted in "Nostalgia");
Here is also my advertisement table that I used at the balka. I varnished it against the rain. New software was shown as disks and tapes separately. I photographed it before it went unreadable.
Vladimir Bogdanovitch vbvzx@narod.ru