*********************************************************************************************** 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 [dw ] dw dw dw squeekpin0 dw dw dw dw ================================================================================ 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 [dw ] dw 0 dw 0 dw accupin0 dw dw dw dw ================================================================================ 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 [dw ] dw dw dw tritone0 dw dw dw 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 [dw ] dw dw dw octode0 dw dw dw dw dw dw (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 [dw ] dw #0 dw dw dw dw dw dw dw dw 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 [dw ] dw dw dw ("core0" to disable, "core0n" to enable) dw dw dw dw dw 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 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 [dw ] dw (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: * 256 + word 5: frequency ch3 word 6: frequency ch4 word 7: * 256 + 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,