Good point. I still haven't found a useful application for this, though.
What I came up with some time ago was this:

   ld bc,DIVIDER     ;DIVIDER < #1000
   ld hl,0
   ld de,!0
loop
   add hl,bc
   ex de,hl
   add hl,bc
   ex de,hl
   ld a,h
   xor d
   out (#fe),a
   ...

It's obviously pretty fast, and 12-bit resolution more or less does the job. But as such, it's still seems quite a waste. I wonder if something more useful can be derived from it.

Part 11: Sound Tricks - Noise, Phasing, SID Sound, Earth Shaker, Duty Modulation

Digital/PCM sound is a powerful and flexible tool, but unfortunately it tends to consume a lot of RAM. So in this part of the tutorial, let's go back to the good old Pulse Interleaving technique, and talk about various tricks that can be used to spice up its sound.


Noise

Historically speaking, 1-bit routines have always been lacking in terms of percussive effects. However, converting a tone generator into a simple noise generator is surprisingly simple, and costs a mere 8 cycles on Z80-based systems. Consider the usual way we generate square wave tones:

   add hl,de           ;add base frequency divider (DE) to channel accumulator (HL)
   ld a,h              ;grab hi-byte of channel accumulator
   cp DUTY             ;compare against duty threshold value
   sbc a,a             ;set A to 0 or 0xFF depending on result
   out (#fe),a         ;output A to beeper port

Now, in order to generate noise instead of tones, one would obviously need to randomize the value held by the channel accumulator. But pseudo-random number generators are slow, so how do we do it? The answer is to simply reduce the quality of the PRNG as much as possible. Believe it or not, adding a single

   rlc h

after the add hl,de operation will provide enough entropy to create a convincing illusion of white noise. But it will do so only if it is fed a suitable
frequency divider as a seed. I usually use a fixed value of 0x2174 in my routines. Other values are possible of course, and may give slightly different results, though most values will just generate nasty glitch sounds instead of noise.

There's a nice side effect that you get for free - you can create the illusion of controlling the volume of the noise by changing the duty threshold. Changing the pitch of the noise however is much more difficult, and requires the use of additional counters. I'm still looking for an efficient way of doing it, if you have any ideas please let me know.

Last note, you can of course also rotate the hi-byte of frequency divider instead of the accu. The result of that however is almost guaranteed to be a glitch sound rather than noise.


Phasing

The Phasing technique was developed by Shiru, and is used to generate the signature sound of his Phaser1-3 engines. It comes at a rather heavy cost in terms of cycle count and register usage, but it's power and flexibility undoubtedly outweigh those drawbacks.

For regular tone generation, we use a single oscillator to generate the square wave (represented by the add hl,de operation). The main idea of Phasing, on the other hand, is to use two oscillators, and mix their outputs into a single signal. The mixing can be done via a binary XOR of the two oscillator outputs (the method used in Phaser1), or via a binary OR or AND (added in Phaser2/3).

   add hl,de           ;OSC 1: add base freq divider (DE) to channel accu (HL) as usual
   ld a,h              ;grab hi-byte of channel accumulator
   cp DUTY1            ;compare against duty threshold value
   sbc a,a             ;set A to 0 or 0xFF depending on result
   ld b,a              ;preserve result in B
   
   exx                 ;shadow register set, yay
   add hl,de           ;OSC 2: exactly the same operation as above
   ld a,h              ;grab hi-byte of channel accumulator
   cp DUTY2            ;compare against duty threshold value
   sbc a,a             ;set A to 0 or 0xFF depending on result
   exx                 ;back to primary register set
   
   xor b               ;combine output of OSC 1 and 2. (xor|or|and)
   out (#fe),a         ;output A to beeper port

As you can see, this method offers a wide range of parameters that affect timbre. The most important one, from which the technique derives its name, is the phase offset between the two oscillators. To make use of this feature, simply initialize the OSC1 accu to another value than the initial value of the OSC2 accu, eg. initialize HL to 0 and HL' to a non-zero value. Especially in conjunction with a slight offset between the OSC1 and OSC2 base dividers, some surprisingly complex timbres can be produced.

Side note: By using a binary OR to mix the signal and keeping the duty thresholds down to a reasonable level, the two oscillators can be used as independant tone generators. This method is used to mix channels in Squeeker and derived engines.


SID Sound

This effect, which derives its name from the key sound that can be heard in many of the early SID tunes, is formed by a simple duty cycle sweep. The velocity of the sweep is in sync with the frequency of the tone generator. Basically, every time the channel accumulator overflows, the duty threshold is increased or decreased. As with noise, this is trivial to pull off and costs only a few cycles. Using the standard tone generation procedure, we can implement it as follows

   add hl,de           ;add base frequency divider (DE) to channel accumulator (HL)
   sbc a,a             ;set A to 0 or 0xFF depending on result
   add a,c             ;add duty threshold (C)
   ld c,a              ;update duty threshold value (C = C - 1 if add hl,de carried)
   cp h                ;compare duty threshold value against hi-byte of channel accu
   sbc a,a             ;set A to 0 or 0xFF depending on result
   out (#fe),a         ;output A

As you can see, this operation costs a mere 4 cycles compared to the standard procedure without duty cycle sweep.


Earth Shaker

This effect is named after the game Earth Shaker, which used a rather unusual sound routine with two semi-independant tone channels, written by Michael Batty. As an actual method of generating multi-channel sound, it is of limited practicality, but it can be applied as an effect to regular Pulse Interleaving at a minimal cost. The core concept here is to continually modulate the duty threshold within the sound loop. Depending on the ratio of the duty cycle change vs the oscillator speed, the result can be a nice chord, phatness, or - in most cases - gruesome disharmony that will strike fear in the hearts of even the most accustomed 1-bit connaisseurs. A simple implementation, as used in HoustonTracker 2 for example, looks like this:

   add hl,de           ;add base frequency divider (DE) to channel accumulator (HL)
   ld a,c              ;load duty threshold (C)
   add a,DUTY_MOD      ;add duty threshold modifier
   ld c,a              ;store new duty threshold
   cp h                ;compare duty threshold value against hi-byte of channel accu
   sbc a,a             ;set A to 0 or 0xFF depending on result
   out (#fe),a         ;output A to beeper port

Duty Modulation

The aforementioned SID sound and Earth Shaker effects are actually basic implementations of a family of effects that may best be described as "Duty Modulation". As a first step into the world of Duty Modulation, let's take the Earth Shaker effect and modify it to change the duty threshold in sync with the main oscillator.

   add hl,de           ;add base frequency divider (DE) to channel accumulator (HL)
   sbc a,a             ;set A to 0 or 0xFF depending on result
   and DUTY_MOD        ;set A to 0 or DUTY_MOD
   xor c               ;XOR with current duty threshold (C)
   ld c,a              ;store new duty threshold
   cp h                ;compare duty threshold value against hi-byte of channel accu
   sbc a,a             ;set A to 0 or 0xFF depending on result
   out (#fe),a         ;output A to beeper port

By syncing the modulation in this way, the nasty glitches of the Earth Shaker effect can be avoided entirely (but also, no chords will be produced). Instead, we can now control harmonic components that share an octave relation with the base note. In other words, we can amplify over- and undertones at will, as long as they are a multiple of 12 half-tones away from the main note.


Things can be pushed even further by decoupling the sync and using a second oscillator to time the duty threshold updates.

   exx
   add hl,de           ;independant oscillator for timed duty threshold updates
   exx
   sbc a,a             ;set A to 0 or 0xFF depending on result
   and DUTY_MOD        ;set A to 0 or DUTY_MOD
   xor c               ;XOR with current duty threshold (C)
   ld c,a              ;store new duty threshold
   
   add hl,de           ;add base frequency divider (DE) to channel accumulator (HL)
   cp h                ;compare duty threshold value against hi-byte of channel accu
   sbc a,a             ;set A to 0 or 0xFF depending on result
   out (#fe),a         ;output A to beeper port

This way, we can create the octave effects from the previous example (by setting the "duty" oscillator to the same value as the main tone oscillator), as well as Earth Shaker style chords, while also gaining better control over the latter. Additionally, some interesting slow-running timbre changes can be achieved by setting the duty oscillator to a frequency near (but not equal to) the main oscillator.

The usefulness of this approach might seem a bit questionable considering the hefty cost in CPU cycles and register usage. However, the required code is almost the same as the one used for the Phasing technique, so with a tiny amount of self-modifying code, it can be implemented in a Phaser style engine at virtually no extra cost.

There's also an added bonus when combining this technique with the noise generator explained above. By setting the duty threshold to the same value as the duty modifier, the duty oscillator can be used as a tone generator, meaning you can actually mix noise and tone on the same channel!

That's all for this time. If you know of any other cool tricks please post them here!

The master of Savage engine strikes again! Thanks for digging this up, Tufty.

xxl, demo itself appears to be one-file, so it should be possible to rip .bin from emulator.

654

(5 replies, posted in Sinclair)

Cheers wink The demo doesn't really show the flexibility of this thing, I just picked one setting for the phaser channel that I really liked, and ch1 is running in standard SID mode. But actually, you can do all kinds of weird shit with it big_smile Hmm, I wonder how it would sound with some filters and volume envelopes on top... well, another time, maybe.

655

(5 replies, posted in Sinclair)

Surprise! Was a bit bored today...

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.

No XM converter obviously, and no mp3 render either for the time being.
Source is on my github, as usual.

I also made a 3-channel core with this effect (Tritone style, no phaser fx), but I don't have time/motivation to finish it atm. Might try to squeeze a few more cycles from that one so I can add it to beepertoy. Or maybe I'll add it to this engine, got an unused flag bit which could be used for switching cores on the fly. Not sure yet.

656

(21 replies, posted in Sinclair)

A quick update on this: Just got the parser to output it's first blob of correct asm data. Unfortunately today is the last day I can work on it for the forseeable future, but I'm glad I got this far. There's still tons of functionality missing, and the code would probably give any self-respecting programmer a heart attack at this point. So long story short, there probably won't be any public release till beginning of 2017.

In the meantime, here's a little preview, to give you an idea how the thing works (it has a name now, too, btw - MDAL aka Music Data Abstraction Language).

The input music file looks like this:

CONFIG=PhaseSqueek

:SEQUENCE
    intro
    pattern0
    [loop]
    pattern0
    pattern2
    
:intro
    A=a1, B=c3, C=e3, GMIX=or, MIXAB=or, MIXCD=or, SPD=$8
    .
    A=a2
    .
    A=a3
    .
    A=a2, C=0
    .

:pattern0
    .

:pattern2
    .

which gives us this:

    dw intro
    dw pattern0
loop
    dw pattern0
    dw pattern2
    dw 0

intro

    dw #b000, fx0, #b000, a1, c3, #4040, #c6, #c6, #0, #b000, e3, #0, #4040, #0, #800
    dw #b085, #800
    dw #b001, #b0c4, a2, #0, #800
    dw #b085, #800
    dw #b001, #b0c4, a3, #0, #800
    dw #b085, #800
    dw #b001, #b0c4, a2, #0, #b0c0, #0, #0, #800
    dw #b085, #800
    db #40

pattern0

    dw #b085, #800
    db #40

pattern2

    dw #b085, #800
    db #40

based on this config:

MDAL_VERSION(0)
USE_SEQUENCE;
USE_PATTERNS;

WORD_DIRECTIVE("dw");
BYTE_DIRECTIVE("db");
HEX_PREFIX("#");


CFG_SEQUENCE {
    USE_END("dw 0");
    USE_LOOP(LABEL, "loop");
    USE_TRACKS(1);
}

CFG_PATTERNS {
    USE_END("db #40");
}
    
CFG_COMMANDS {
                
    WORD("FX","fx0");    
    WORD("A", 0, USE_LAST_SET|USE_RESTS(0));
    WORD("B", 0, USE_LAST_SET|USE_RESTS(0));
    BYTE("DA", $40, USE_LAST_SET);    
    BYTE("DB", $40, USE_LAST_SET);    
    BYTE("SIDA", $c6, USE_LAST_SET|FORCE_SUBSTITUTION("off"=$c6, "on"=$ce));
    BYTE("SIDB", $c6, USE_LAST_SET|FORCE_SUBSTITUTION("off "=$c6, "on"=$ce));
    BYTE("ESA", 0, USE_LAST_SET);
    BYTE("ESB", 0, USE_LAST_SET);
    WORD("PAB", 0, USE_LAST_SET);
    WORD("C", 0, USE_LAST_SET|USE_RESTS(0));
    WORD("D", 0, USE_LAST_SET|USE_RESTS(0));
    BYTE("DC", $40, USE_LAST_SET);
    BYTE("DD", $40, USE_LAST_SET);
    BOOL("NC", false, USE_LAST_SET|FORCE_SUBSTITUTION("off"=false, "on"=true));
    WORD("PCD", 0, USE_LAST_SET);
    
    BYTE("DRUM", 0, FORCE_SUBSTITUTION("kick"=$40, "hat"=$80));
    BYTE("GMIX", $b0, FORCE_REPEAT|FORCE_SUBSTITUTION("or"=$b0, "xor"=$a8, "and"=$a0));
    BYTE("MIXAB", $b0, USE_LAST_SET|FORCE_SUBSTITUTION("or"=$b0, "xor"=$a8, "and"=$a0));
    BYTE("MIXCD", $b0, USE_LAST_SET|FORCE_SUBSTITUTION("or"=$b0, "xor"=$a8, "and"=$a0));
    BYTE("GSPD", $10, GLOBAL_CONST);
    BYTE("SPD", $10, FORCE_REPEAT);
}
    
    
CFG_FIELDS {
    WORD(0, REQUIRED(), SET_IF(!(FX&A&B&DA&DB&SIDA&SIDB&ESA&ESB&PAB&C&D&DC&DD&NC&PCD&MIXAB&MIXCD), 4), SET_IF(!FX, 1), SET_IF(!(A&B&DA&DB&SIDA&SIDB&ESA&ESB&PAB&MIXAB), $80), SET_HI(GMIX));
    WORD("fx0", SET(FX));
    WORD(0, REQUIRED(A|B|DA|DB|SIDA|SIDB|ESA|ESB|PAB|MIXAB), SET_IF(!(A&B), 1), SET_IF(!(SIDA&SIDB&ESA&ESB), 4), SET_IF(!DA&DB, $40), SET_IF(!PAB, $80), SET_HI(MIXAB));
    WORD(1, REQUIRED(B), SET(A));
    WORD(2, REQUIRED(A), SET(B));
    WORD($4040, SET_HI(DA), SET_LO(DB));
    WORD($00c6, SET_HI(ESA), SET_LO(SIDA));
    WORD($00c6, SET_HI(ESB), SET_LO(SIDB));
    WORD(3, SET(PAB));
    WORD(4, REQUIRED(C|D|DC|DD|NC|PCD|MIXCD), SET_IF(!(C&D), 1), SET_IF(!(DC&DD), $40), SET_IF(!PCD, $80), SET_HI(MIXCD));
    WORD(5, REQUIRED(D), SET(C));
    WORD(6, REQUIRED(C), SET(D));
    WORD($4040, SET_HI(DC), SET_LO(DD));
    WORD(7, SET(PCD));    
    WORD($1000, REQUIRED(), SET_HI(SPD), SET_LO(DRUM));

    REQUIRE_SEQ_BEGIN();    
}

Guess what, it's time for a new version! HT2.20 comes with new effects, improved speed control, and a savestate manager utility for importing tracks from older versions. Full list of changes can be found in the OP.

Tutorial vid demonstrating some of the new fx: https://www.youtube.com/watch?v=bBXjOJTFe5k
New demo track: https://soundcloud.com/irrlicht-project/hrd-4-da-money

download HT2.20

658

(135 replies, posted in Sinclair)

Cheers guys, I also think all the tracks were pretty damn good. Also, great to see a new face in the compo.

To my shame I have to admit I didn't recognize the engine used for Road Song yikes Modded Tritone, you say? Interesting, I presume you had a hand in this, introspec?

659

(20 replies, posted in Sinclair)

Reverted the fix and applied another one, which seems to be working. Latest fix is on github now.

660

(3 replies, posted in Sinclair)

Horray, it's officially out! And my copy of the CD is sitting proudly on top of the stereo smile

661

(20 replies, posted in Sinclair)

Ok, found it. It's a bug in Squeeker Plus itself, rather than the converter.
What's happening is that in order to prevent ch4 from being left in a permanent "high" state after applying the slide effect (ie. counter hi byte + duty > 0xff, which would cause channel overload), the channel counter is reset on every tick. That's fine for higher notes, but it's deadly for bass notes.
I've applied a little temp fix for this, but I'm not entirely happy with that solution yet. I've pushed the changes to github for now, though.

Btw, something I forgot to mention regarding detune - contrary to standard XM behaviour, it is only effective in conjunction with a note trigger, and will live till the end of a note rather than the end of a row.

662

(20 replies, posted in Sinclair)

Seems I've introduced another bug with the latest changes. Under some circumstances ch4 appears to not generate the correct note frequencies. It only happens sometimes, haven't quite figured out why. Let me know if you encounter this bug as well.

663

(20 replies, posted in Sinclair)

I agree, the other way around would be more logical. But it would also be much more complicated to detect in the converter, so for the time being I can't be arsed. I've (hopefully) fixed the detune though.

664

(20 replies, posted in Sinclair)

Thanks mate. I've made a new commit, hopefully this should fix the issue. There might be more horrors lurking in the abyss of xmkit though.

665

(21 replies, posted in Sinclair)

I'm afraid an ABC/MML converter would be very difficult to pull off. A note/sequence importer from XM or perhaps MIDI would be easier.

Shiru, yes, good point. I still want to add some configurability right from the start though, because I want to improve my C++ skills a bit, too.

In any case, it'll take a while before I have anything to show, as I'm planning on taking a break from coding next week.

666

(20 replies, posted in Sinclair)

You're right, envelopes take precedence over channel volume, not the other way around. Sorry 'bout that...

For the rest, it sounds like some good ol' bugs... I'll look into it, perhaps tomorrow if I can find some time.

667

(20 replies, posted in Sinclair)

Cheers wink Channel volume overrides the envelope. Multi-point envelopes are taken into account, though there's a chance they aren't parsed correctly, so check the asm in case something sounds fishy.

668

(21 replies, posted in Sinclair)

Thanks mate wink

Any more thoughts on the language thing? I've already worked out a rough draft for the implementation. Think I'll do the parser in C++ after all (since I can't really be bothered to learn yet another language atm, and I don't feel like using Perl either). The parser will be customizable via config files, which will allow for creating extra commands and so on. Well, we'll see how that goes, I really have zero experience in writing such a thing.

669

(20 replies, posted in Sinclair)

Whoa, dafuq did that happen? Yeah, the xmkit version from zbmod is not compatible with xm2squeekerplus. At the moment xmkit is still a rather dysfunctional mess, and a prime example of a bad programmer interface. I though "Oh, I'll quickly make a library so I don't have to rewrite the whole XM conversion code every time" but I greatly underestimated the amount of work involved, and lack of experience didn't help either.

Anyway, I've added the required files to the repo. Thanks for reporting!

670

(21 replies, posted in Sinclair)

After studying the ABC standard a bit, I'm actually leaning more towards defining a new standard. ABC is very strongly focused on score notation while offering very little in terms of timbre control. It does actually provide most of what we need (there are tools for creating user-defined commands, macros, etc), but ultimately using those would cause quite a mess. Besides, it seems inconvenient for parsing. Furthermore, I kind of prefer having a traditional pattern structure, rather than long strings of commands.

In any case, using calls/macros is a good idea.
At the moment, I'm thinking something along these lines

:order               // "order" would be a reserved keyword.
^intro               // names could be freely chosen
(loop)
^1                    // or short-handed by supplying only a number which will be expanded depending on context, ie. this will look for "pattern1"
...
// end directive is optional, as each block end can be determined by following :

:intro
A=a1  B=r  C=c3  D=e3  CFG=^1,^2,^3  FX=none        //note length fixed, ABCD=operator/channel, number after note name denotes octave
.                                                                                      //no changes in this row
A=a2  DUTY_A=#20
.
A=a1  B=a1-#1                                              // # denotes usage of immediate (hex) value instead of string literal
A=#800 FX=^1

:cfg1
GMIX=OR        // so alternative notation for phaser would be: GMIX=#b0

:cfg2
PHASE_AB=#1000
PHASE_CD=#0
DUTY_A=#40
DUTY_B=#40
DUTY_C=#20
MIX_AB=OR
MIX_CD=XOR

:cfg3
DUTY_D=#20
SID_A=OFF
SID_B=OFF
ES_A=OFF
ES_B=#1

:cfg4
GMIX=XOR

:fx1
A=C2
.
(loop)
A=c3 CFG=^4
.
A=c4 CFG=^1
.

Admittedly, it's still quite a mess, and nothing more than a rough draft.

Regarding independant patterns per channel vs multi-channel patterns: There are certain benefits to having independant patterns per channel, but I think that with Phase Squeek, it would make things super messy, both for editing and for parsing.

671

(21 replies, posted in Sinclair)

Cheers guys wink

I quite like the idea of using a human-readable text interface. And yes, from the looks of it I would definately prefer ABC over MML. Have not looked much into either of them though tbh. In any case I think it's best to use an existing standard rather than creating our own.

The main question is if and how certain aspects like timbre settings (in case of Phase Squeek, that would be duty, phase, coupling modes, SID enable/disable, Earth Shaker setting, noise enable/disable, noise pitch) and the whole FX table business. I think we'll be making heavy use of the I: syntax ("Instruction"). But I really have to look more into the ABC standard to see how it could be done. Ultimately it should be done in a way that is not only usable for Phase Squeek, but also for other "un-trackerable" engines. So let's take some time to brainstorm about this - suggestions are very welcome!

Btw perhaps a thing worth noting, unlike with Tritone FX, the FX table syntax in Phase Squeek is almost exactly the same as the pattern syntax, with only two minor derivations.

672

(13 replies, posted in Sinclair)

Working on speccy stuff? Blasphemy! big_smile

The problem is, drums > 5 can't be entered in Beepola iirc. I'd think that's a hard limit encoded with the engine somewhere, since with other engines Beepola quite happily accepts higher numbers. So, basically it just might be a question of finding that number and changing it. But yeah, chances to find it in the binary are probably not exactly great.

673

(21 replies, posted in Sinclair)

I said I'm not turning this into a full engi... ah, damnit!
Lo and behold: Phase Squeek, aka TOUPEE, the Totally Overpowered, Utterly Pointless Extreme Engine

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.

source code
download (no XM converter included)
UPDATE: demo tune on soundcloud

Some notes on the demo track (also Included in the download package):

- The intro and first part demonstrates the 4-channel mode, in which the engine basically acts as a Squeeker Plus clone.
- In the second part, operators 1 and 2 are linked to create the phasing bass, while channel 3 and 4 make some use of the fx table feature.
- In the first half of the third part, various different configurations for the two-op mode on ch1 are demonstrated, including the SID and Earth Shaker effects. The other channels are silent save for some occasional noise (this time without using tables, hence it sounds more rough)
- In the second half of the third part, the single channel mode is demonstrated with 3 and 4 operators in use, and various different configurations of phase, detune, coupling mode and so on.

674

(135 replies, posted in Sinclair)

So I was curious whether it's possible to combine Shiru's Phaser technique with zilogat0r's Squeeker method. Turns out it works surprisingly well!
The downside is of course that the sound is somewhat less clean than with proper pulse interleaving. But there are various benefits to having only one OUT in the loop. It's not only faster, but also there's no need to keep the cycle count down because there's no need to render multiple volume levels.

I'm not motivated to turn this into a proper engine at the moment, since it would be impossible make an XM converter for it anyway. But if anyone wants to play around with this, please do!


EDIT: Added the good ol' adc a,n SID and Earth Shaker effects on channel 1. Because, why not. This brings the total of configurable parameters for the first channel up to 10:

- frequency OP1
- frequency OP2
- duty OP1
- duty OP2
- SID on/off OP1
- SID on/off OP2
- ES duty modulation OP1
- ES duty modulation OP2
- Phase
- Mixing method (xor | or | and)

All nicely aligned to 224 t-states big_smile

The next step could be to add some modulators which would update the parameters once per 256 loops or so. Or maybe digi rendering with lo-pass... ehhh... I've got a strange feeling this is getting outta hand... yikes

675

(13 replies, posted in Sinclair)

introspec, I meant because Follin player is Beeper + AY drums, and yours will be AY + Beeper drums wink

abrimaal, nice work, and thank you for sharing the sources (and welcome to the new 1-bit forum, btw). Indeed, it is always a problem to find a way to edit music for new drivers. That's why I'm now trying to create a C++ library for extracting data from XM files. Ideally, this would allow for very quick creation of XM converters, but at the moment it is still too inconsisten and instable to be used productively.

In case of doombass, perhaps FrankT could help unlock the extra drums? He's done quite a bit of patching in the Beepola code, so he might have an idea where the relevant parameter for the limit of drums is hidden. Frank, where are you man?

EDIT: Couldn't resist trying to implement the Buzzer effect. Voilà.