1 (edited by utz 2016-08-12 10:12:39)

Topic: new engine: Phase Squeek

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.

Re: new engine: Phase Squeek

sweet :-)

Re: new engine: Phase Squeek

Yes another masterpiece that is also really difficult to support in a tracker.

I thought, maybe instead of the XM conversion or all-for-one tracker we can design and create a MML-like system for these engines? One that compiles a human readable text into a AY/TAP/BIN (so you can hook it up to the Notepad++ and hear the result just by pressing F5 or something). Text allows more flexible input than tracker's row/column based grid, like variable number of channels and parameters.

Re: new engine: Phase Squeek

Just listened on soundcloud, excellent!

Another remarkable engine ever expanding the unique sound of 1-bit beeper!

Txt convertor idea sounds cool too.

5 (edited by garvalf 2016-08-13 07:08:47)

Re: new engine: Phase Squeek

Cool. And even beyond coolness: an other incredible engine.

A MML like converter would be a good idea.
I don't really enjoy the MML syntax itself (not very logical), and prefer the ABC notation syntax: http://abcnotation.com/

A comparison:
https://lut.im/KhLBayqqz5/z6oGgMJvmama32Wy.png

In ABC :

X: 1
M: 4/4
L: 1/8 % you can define the base note here
Q:1/4=120
K:C % 0 sharps
C2 D2 E2 F2|  G2 A2 B2 c2| d2 e2 f4| g2 ab c'4|]

In MML:

t120 cdefgab>cdef2ga8b8>c2

What I like in abc, we have at least 4 visual octave ranges: C, C c and c' (C, being the lower). It's possible to add marks to get even lower, for example C,, or higher (c'')
It's also easier, in my opinion, to read (and write) music this way. Just by a quick glance, we can see if a part is lower than the other. After a few < > < < > in MML, it's more tedious.
- In ABC, we use the opposite for length of notes. If 1 is the base, 2 means it doubles the base length.
It may just be an habit, but the advantage is you can count to check if your mesure or part is complete or not:
d2 + e2 + f4 = 8
g2 + a + b + c'4 = 8

Of course, using MML would be better for such a tool, because MML is widespread among chipmusician. And there is a very good tool to convert from midi to MML: http://3ml.jp/download.html (you can export tracks individually)

I've written a few tips and useful links about MML there:
http://garvalf.online.fr/index.php?page … s_pmd98.en

(sorry for highjacking this thread!)

Re: new engine: Phase Squeek

garvalf, totally agree on the syntax for notes and durations. I don't like MML for the same reasons, that's why I said 'MML-like'. ABC looks much better.

Re: new engine: Phase Squeek

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.

8 (edited by Shiru 2016-08-13 17:59:09)

Re: new engine: Phase Squeek

I think that to keep things under control and in a convinient way, we should use ABC or MML as a base, but not fully match to the standard. I.e. add convinient shortcuts for things.

For one, we can implement a 'subroutine', just like in BASIC. The subroutine can be either another sequence of notes, or a set of parameter changes. I.e. there would be no instrument per se, just immediate parameters change that could be abstracted as subroutines. For example, ^ used as a call operator (to keep it short) working by a label:

^ins0 C2 E2 G2 R2 ^ins1 C2 E2 G2 R2

ins0:
duty=50
detune=2
ret

Also, to keep it short, I'd suggest to allow using a note name without duration by remembering the last value, i.e. C2 E2 G2 R2 equal to C2 E G R.


Using calls, we actually won't need to have an order list equivalent. Just write patterns with labels and rets, then the entry point will be just series of calls.

^pattern1 ^pattern2 ^pattern1 ^pattern3
stop

pattern1:

C2 E2 G2 B2

ret

...

One thing to think deeper is how to use chords in an convinient way, not split per a number of data sequences. Maybe some operator like + (C+E+G2 for Cmaj).


I imagine this system as being written in some scripting language, such as Python, with infrastructure a bit similar to the 1tracker's, i.e. the compiler script generates text data (DB/DW), then an assembler (maybe just SjAsm/Pasmo, or also written in the script language) gets invoked to compile that into AY/TAP/SNA/etc.

Re: new engine: Phase Squeek

The ABC notation standard is quite exhaustive (and still evolving), but it's more made toward folk / classical users, using real instruments. Yet a common use for extending it is to use the comment symbol % so it won't interfere with other applications. For example in a program which can convert to midi, one can add this:
%%MIDI channel 1
%%MIDI program 20 % reed organ
%%MIDI transpose 0

There are a bunch of applications for working with abc files, for example for converting from midi, for transposing, to printing to pdf, for converting to lilypond etc. (I've been using abc for almost 20 years so I like it quite much, I've transcribed many tunes with it).

The MML problem is there are several software using it, but they use different syntaxes, so you can get a tune in MML which won't compile because of some incompatibilities. As far as I've seen, most MML allows to define macros, for making differents parts or even some rythms. With the 3ML tool, it's ok for using with midi tunes (even if you have to manually import every track). MML is more popular among chip musicians so it might be a better choice.

10

Re: new engine: Phase Squeek

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.

Re: new engine: Phase Squeek

Returning back to the topic: utz, I always knew that beeper was more rock'n'roll than AY, but massive thank you for providing plenty of convincing evidence recently.

I always thought that beeper must be good for emulating overdriven instruments.

12

Re: new engine: Phase Squeek

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.

13 (edited by Shiru 2016-08-19 19:03:03)

Re: new engine: Phase Squeek

I think it is better to start simple, without adding too many features, and without expecting to expanding the same code to new engines. In general, it needs to be a prototype, to see how convinient the current idea could be. Later we can redo it as an improved, expandable version, having better understanding how to design such thing.

Re: new engine: Phase Squeek

> Any more thoughts on the language thing?

none, as long as the notes can be defined in a way that can be easily be imported / exported from other tools (like mml or abc can be) the rest will probably be fine.
For the record, there are already some abc parsers in lua, in C https://sites.google.com/site/abcparser/
and a cool preprocessor: http://abcplus.sourceforge.net/#abcpp

15

Re: new engine: Phase Squeek

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.

Re: new engine: Phase Squeek

oh yes, midi, mod or XM import would be very cool too!
There are various converters between all those formats so we're never stuck.

17

Re: new engine: Phase Squeek

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();    
}

18

Re: new engine: Phase Squeek

I've got some very good news: The core table parser is implemented and working. In other words, MDAL just generated the first complete and (more or less) working music.asm for PhaseSqueek. There's a number of things that still need tweaking, but we're definately getting there.

Re: new engine: Phase Squeek

congrat! So now there are already 3 engines... well done.

20

Re: new engine: Phase Squeek

Not 100% there yet with PhaseSqueek, some details are still missing. For example, I've recently added label prefixes, to minimize the change of name collisions (eg. if you name a pattern "pattern1", it'll be named "mdp_pattern1" in the asm output. However, I still need to implement this for commands that set a pointer (which the PhaseSqueek config uses). Once these things are taken care of though, MDAL should be able to support almost all existing beeper engines, except those that use multi-track sequences and/or samples.

21

Re: new engine: Phase Squeek

Alright, we've got a working PhaseSqueek config! It's pretty complete, except that MDAL doesn't support tables that aren't linked from a pattern yet.
For example something like this doesn't work yet:

:SEQUENCE
    pattern1
:pattern1
    A=c1, FX=fx1
    .
:fx1
   A=c1
   A=d1
   A=e1
   FXJUMP=fx2
:fx2
   A=f1
   A=g1
   FXJUMP=fx2

I have to say, MDAL makes things easier, but the engine is still a major p.i.t.a. to use. You have to be very careful especially when constructing tables, because of the data format quirks. For example, if you have A and B set in your pattern, and want to use a table that modifies A, then you should set B again at the start of the table. This is because the player expects a value for B when A is set, but mdalc has no means of knowing what that value should be, and thus will fall back to the default value if you don't tell it to do otherwise. (Setting the value once is enough, mdalc will use the value that was last set from this point on). Likewise, SIDA requires SIDB, ESA, and ESB and vice versa. Also, when in doubt, use PAB/PCD=0 to reset the phase.

Post's attachments

test.tap 2.01 kb, 5 downloads since 2016-10-31 

You don't have the permssions to download the attachments of this post.

22

Re: new engine: Phase Squeek

sounds very good