51

Re: next gen engine ideas

I believe there may be another way of fak... err, I mean generating a saw wave on beeper. For this, we need to look at the frequency spectrum, rather than the waveform. In the frequency domain, a square wave is characterized by having a peak at each odd harmonic. That means, for a 440 Hz, 50% duty square wave, frequency components will be present at 440*3, 440*5, 440*7 Hz, and so forth, but not at 440*2, 440*4, 440*6 Hz etc.
A saw wave, on the other hand, peaks at both even and odd harmonics. Thus it can be approximated by mixing a series of square waves with frequencies of f, f*2, f*4, f*8, etc. With the "fast accumulation" technique (add hl,de \ ld a,h \ out (#fe),a) we can easily achieve this by rotating A to get the required multiples. Doing this with 3-4 frequencies should already give a reasonable approximation of a saw, because the missing components will be high enough to fall out of the range at which humans can reliably detect the difference.

52

Re: next gen engine ideas

Alright, got a new idea - use a "state memory". Now wtf is a state memory? Think about how we implement accumulative pin pulse engines (Octode XL, for example). We basically "remember" the state of the carry flag from add hl,de for a given time (which, in an accumulative pin pulse engine, will control the volume). But in pulse interleaving engines, we evaluate the state only once and then discard it immediately. But it might be useful to actually remember it for some time. For example, we can implement a primitive low-pass filter like this (excuse the sloppy code, it's early in the morning big_smile)

   ld hl,0        ;counter, clear it
   ld de,#40      ;freq divider
   ld b,0         ;"state memory"
loop
    add hl,de     ;nothing special going on here, just adding da stuff
    ld a,h        ;HL bit 12 = output state
    out (#fe),a
    
    and #10       ;store the current state in state memory
    or b
    ld b,a
    
    rrca          ;get old state from 8 loop iterations ago
    ;rrca         ;2x rrca = high cutoff, 1x rrca = low cutoff (filter moves slower)
    nop

    nop           ;timing
    
    out (#fe),a
    
    and #ef       ;delete old state from state memory
    ld b,a
    
    ld c,0        ;timing
    
    jr loop

High-pass could be implemented in a similar fashion, because HP_output is basically just (original_output - LP_output). There could be other uses for this "state memory" thing as well.

53

Re: next gen engine ideas

Proof of concept for my idea about saw wave generation:

;saw wave via square wave transform ([f,a]+[2f,½a]+[4f,¼a]...)

    ld hl,0
    ld de,#40
    ld c,#fe
    
loop
    add hl,de    ;11
    
    ld a,0        ;7    ;timing
    ld a,0        ;7    ;timing
    ld a,0        ;7    ;timing
    nop           ;4
    
    ld a,h        ;4

    out (c),a    ;12__64   ([f, a])
    rrca         ;4
    out (c),a    ;12__16   ([4f, ¼a])
    rrca         ;4
    ds 4         ;16
    out (c),a    ;12__32   ([2f, ½a])
    jr loop        ;12
Post's attachments

test.tap 120 b, 2 downloads since 2016-11-29 

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

54

Re: next gen engine ideas

Been doing some thinking about vibratos. Here's an algo that is reasonably fast, has configurable parameters, and doesn't require a table lookup:

    ld hl,0
    ld de,note_divider
    
    ld c,1                    ;vibrato strength (max 0xf)
    ld b,2                    ;position init (must be ½ of vibrSpeed range - else detune)

loop
    add hl,de        ;11
    ld a,h            ;4
    out (#fe),a        ;11

    ld a,e            ;4
    jr nc,noVibrato        ;12/7

    ret nc            ;5        ;timing
vibrDir                    
    inc b            ;4        ;initial direction (probably needed as configurable parameter)
vibrSpeed equ $+1
    bit 2,b            ;8        ;speed (see above, bit 3 -> ld b,4 | bit 2 -> ld b,2...)
    jp z,vibrDown        ;10
                    
vibrUp
    add a,c            ;4        ;DE += C
    ld e,a            ;4
    adc a,d            ;4
    sub e            ;4
    ld d,a            ;4    
    
    jr loop            ;12
                ;96    

vibrDown
    sub c            ;4        ;DE -= C
    ld e,a            ;4
    sbc a,a            ;4    
    add a,d            ;4            
    ld d,a            ;4    
                    
    jr loop            ;12    
                    
    
noVibrato
    ;... waste some t's
    jr loop            ;12
                ;96

I have a feeling that this thing can be optimized further by using an sbc a,a fallthrough solution, but haven't managed to implement it for the downward slide yet. Let me know if you have any ideas for this.

Re: next gen engine ideas

A random idea for an engine - basic 1-bit speech synthesizer (like ones that Mister Beep used in some intros to his songs) designed to make music. Something like that: one channel for variable pitch one-shot and looped samples for consonants and vowels, another channel for tone (Phaser-like maybe) and non-interrupting drums (slide based, optional noise). Besides vowels, some basic looped waveforms could be used to create musical parts on the first channel.

As for controls, something like AlterEgo, but simplifed. Like, array of strings of syllable-separated transcription of the text, automatically loops on the vowels, advances to the next syllable (and pitch) with a new note.

56

Re: next gen engine ideas

As far as singing speech synths go, there's of course tavzx: https://www.youtube.com/watch?v=KkZKDJwwb2o
I agree, would be interesting to have something like this in an actual music engine. However, I'd be more interested in implementing actual formant synthesis. I've done a sample-based speech synth a couple of years ago (also with variable pitch btw), it's pretty boring work imo.

Re: next gen engine ideas

Hi guys

I think this is a great idea. As you know, I've always liked to try and include voice-like sounds in my Beeper tunes,
1-Bit Mechanistic, Mechanoid etc.

An engine I'd love to hear is a rombeep one that converts voice sounds right down to basic beeps. Almost like the effect used sometimes on synthpop music where a vocoder effect is turned up to the max.

I've thought of trying to analyse the waveform of some allophones and manually work out a 'beep-set' myself which could be used in a Beeper tune.

I tried it on my cover of 'Difficult for Weirdos' right at the end.

Another Beeper engine idea is QChan+
A hybrid engine with an AY bass channel (buzztone etc.)

I thought maybe one of the channels could be played as standard QChan but also the same notes as AY bass?
That way the song data could be used and exported from Beepola and incorporated into the Qchan+ engine .asm ?

What do you think utz????

58

Re: next gen engine ideas

Well, trying to imitate the waveforms of the allophones is basically already a sort of proto-formant synthesis wink

Hybrid Qchan would be doable. Generally, almost any beeper engine can be combined with AY without too much trouble. The main problem is that adding AY would significantly increase row transition noise on most engines, because (re)loading the AY registers takes a lot of time. The other problem is volume balance. For example the classic Qchan is not a good candidate for combining with AY buzzer, because the buzzer is much, much louder. This is why I chose Squeeker-type synthesis for my hybrid experiment, because this type of synthesis produces very loud sound, and it also cloaks row transition clicks pretty well.

Well, as I said earlier, I've retired from writing beeper engines for the time being. So don't put your hopes on me. I do hope though that someone else will pick up these ideas, and I'm of course more than willing to help if somebody is to take up the challenge.

Re: next gen engine ideas

Thinking on the 1-bit SuperSaw on ZX and messing up with assembly code a bit, I tried this thing. The idea behind it is the early electronic orgrans that used frequency dividers to form sound registers. So only one real counter here. Can't remember if we ever used something like this?

    ld hl,0
    ld de,400
    
loop
    
    add hl,de
    ld a,h
    cp #80    ;duty 1
    sbc a,a
    out (#fe),a

    push hl
    
    add hl,hl
    ld a,h
    cp #80   ;duty 2
    sbc a,a
    out (#fe),a
    
    add hl,hl
    ld a,h
    cp #80   ;duty 3
    sbc a,a
    out (#fe),a
    
    pop hl
    jp loop

This is one channel with 16-bit adder, the usual idea with duty cycle control like in Tritone. The trick is to generate a number of octave doubled derivatives (phase synced, though) by multiplying the adder by 2 (adding the adder to itself) a few times, two in this example. It adds octave doubles to the sound. Interesting thing is that the three duty cycles kind of have a limited control on the strength of the octave harmonics.

Another thing is that just applying a few duty checks to single unchanged adder also affects the timbre in a way:

    add hl,de
    ld a,h
    cp #80
    sbc a,a
    out (#fe),a

    ld a,h
    cp #08
    sbc a,a
    out (#fe),a

60 (edited by utz 2017-04-05 11:28:01)

Re: next gen engine ideas

The first example can be done faster with 12-bit counters, at the cost of loosing variable duty:

   add hl,de
   ld a,h
   out (#fe),a
   rrca
   out (#fe),a
   rrca
   out (#fe),a

Second example is very powerful. One can create all sorts of waveforms with this, especially if you also play with the distances between the OUT commands. If I understood fourier transformations, I'd have some great fun with this...

My idea was to use a free-running counter. Original idea of an 8-bit counter didn't work, so here is a pretty clumsy version with a 16-bit counter:

    ld de,#80
    xor a
    ld h,a
    ld l,a
    ld b,a
    ld c,a
    
loop
    out (#fe),a    ;11__36
    add hl,de      ;11
    inc bc         ;6
    ld a,h         ;4
    nop            ;4
    out (#fe),a    ;11__36
    add a,b        ;4
    ld r,a         ;9
    jr loop        ;12

Suprisingly it actually works, but wasting a whole 16-bit reg on this seems rather wasteful. Though on the other hand, one free-running counter can serve multiple channels, so maybe not so bad after all.

Edit: On second thought, that register is maybe not wasted at all... because it might be possible to use the frame length counter for this :D
Edit2: Trying out the idea in BeepModular. The effect is less pronounced here because of the volume difference (48 vs 64t), but generally abusing the timer for this seems like a good idea.

Post's attachments

test.tap 929 b, 5 downloads since 2017-04-05 

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

Re: next gen engine ideas

I can't say much about this, but it sounds indeed great!

62 (edited by utz 2017-06-07 20:23:05)

Re: next gen engine ideas

Another 1-bit puzzle cracked: How to generate a triangle wave without wavetable lookup. There are some killer modulation effects that you can do with this as well, but I still need to find a few free t-states in order to implement those for 2 channels.

Edit: Ok, got it. Here's a shorter and faster version, 11 t-states free which will be enough to pull of the modulation effects.

sloop
    add hl,de        ;11
    
    ld a,0           ;7    ;timing
    nop              ;4    ;timing
    
    ld a,h           ;4
    rlca             ;4
    sbc a,a          ;4
    xor h            ;4
    
    rrca             ;4
    out (c),a        ;12__64
    rrca             ;4
    out (c),a        ;12__16
    ds 4             ;16
    rrca             ;4
    out (c),a        ;12__32
    
    jp sloop         ;10

Edit2: Example with modulation effect attached.

Post's attachments

triangle_modulated.tap 133 b, 4 downloads since 2017-06-07 

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

Re: next gen engine ideas

Cool sound utz smile

64 (edited by utz 2017-06-11 18:57:41)

Re: next gen engine ideas

Hmmf, tried mixing 4 triangle waves. It works, but it sounds rather awful. Not sure why that is. Of course, with the volume level reduced to two bits per channel, the sound will be a bit more distorted. But it shouldn't create all that high frequency fizz. And even when pairing notes (same note on ch1/2 and ch3/4), it's still much more noticable than in pytha, even though the core of this one is faster (200t vs 216t in pytha). Any ideas? Is it maybe because the level changes less often? It'd be great to be able to use the "one counter update per sound loop iteration" trick on this. Because then we could modulate our triangle osc with another triangle osc, which means we'd have primitive FM synthesis running. Well, guess I'm dreaming too much.

Edit: Attached proof-of-concept single channel FM example. It's incredibly simple, 2 ops only, so no change over time. Works but sounds terrible, unfortunately.

Edit2: Did some more tests. One thing I tried was to apply a simple low-pass filter (actual_vol = (last_vol + current_vol) / 2) - no luck. Also tried a very fast routine, mixing 2 triangles in 112t. Even that creates significant parasite tone. So either there's something wrong with my algorithm, or 4 levels is simply not enough to render a passable triangle wave.

Edit3: Sure enough, I can reproduce the effect with a hand-drawn sample in Milkytracker. So the noise is definately caused by the reduced number of volume levels. Damn! I'm afraid that means FM synthesis just isn't going to happen, at least not on 48K.

Post's attachments

fm-demo.tap 201 b, 3 downloads since 2017-06-11 

main.asm 1.95 kb, file has never been downloaded. 

test.tap 324 b, 2 downloads since 2017-06-11 

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

65 (edited by Shiru 2017-06-16 04:34:54)

Re: next gen engine ideas

There is a few games with seemingly unique engines that weren't used anywhere else. What they has in common is the strong vibrato on the tone channel, which I think is underexplored area in modern engines.

Saboteur and Sigma 7 engines has one tone channel and noise drums, Sigma 7 also has phasing effects going on the tone channel.

Galaxy Force has as two channels of tone noise drums. The second channel sounds somewhat like ZX-10.

Maybe we could somehow exploit the saw/triangle generator for vibrato? Triangle should be good enough for this use. Should be easier than FM, too.

Re: next gen engine ideas

Recently came across a game with a nice engine I'd not heard before.

Bubble Dizzy (1991) with music by Lyndon Sharp.

Sounds 2 channel plus digi drums

smile

67 (edited by Shiru 2017-06-18 02:06:05)

Re: next gen engine ideas

Wow, totally missed it too. Really cool one. Seems to be next version of the Lyndon Sharp's engine. Thanks a lot for pointing out.

68

Re: next gen engine ideas

Wow, didn't know about Bubble Dizzy either. Seems the music is mis-attributed to Dave Whittaker on WOS.

I agree, we need more vibrato on the beeper. Hey, I did post a vibrato routine earlier in this thread wink That one takes 96 cycles though, we definately need to do better. The triangle generator in it's current form wouldn't be usable as the algorithm produces an off-by-one error on the downward movement. But perhaps it's possible to derive something from that. I'll think more about it when I'm back from vacation.

Hmm, Sigma 7 has some brilliant glissandos as well. Wonder if those are hard-coded, or if there's a clever algorithm behind it.

Re: next gen engine ideas

I spoke to Lyndon Sharp yesterday on facebook (he is currently working on music for the Spectrum Next).

I told him about the bubble dizzy engine being extracted and incorporated into 1tracker 0.26.

He says the bubble dizzy music was actually music reused from a game called rally cross but with 2 re-sampled drums, although he says he likes the drums but can't actually remember doing the tweak smile

Anyway he said to tell Shiru to keep up the good work smile

And if he fancied adding these newly found drums to the main kit it would be good smile

Not sure if he means his original engine?

70 (edited by Shiru 2017-06-21 02:23:27)

Re: next gen engine ideas

Music in these games is the same indeed, pitched a bit differently, and with different drums.

I didn't look too much into Rally Cross, but by the sound and quick glance at the code it is the same engine as in Zanthrax and other games, i.e. the first version. You can guess some sampling process has been involved into making these drums, but they're not really sound like normal samples (actually pretty cool, unlike anything else).

Bubble Dizzy version of engine has clearly defined traditional samples. The code is very different, not a small tweak, but a complete overhaul. Music data format is the same, though. This and the fact that sound tone is the same, makes me sure it is indeed a second version of the engine.

71 (edited by utz 2017-07-01 21:22:38)

Re: next gen engine ideas

Been thinking about the Earth Shaker method again. As far as I understand, it can essentially be implemented like this:

    di
    ld sp,#292        ;freq divider ch1
    ld bc,#1b7        ;freq divider ch2
;    ld hl,0            ;accu ch1
;    ld de,0            ;comparator/accu ch2

loop
    add hl,sp    ;11
    ex de,hl     ;4
    add hl,bc    ;11
    ex de,hl     ;4
    ld a,l       ;4    ;cp hl,de
    add a,e      ;4
    ld a,h       ;4
    adc a,d      ;4
    sbc a,a      ;4
    out (#fe),a  ;11
    ld a,0       ;7    ;timing
    jr loop      ;12
                 ;80

What I don't understand is how to reliably control the pitch. Usual note dividers often don't seem to work as intended. Is this just a limitation of the algorithm, or is do the dividers need to be adjusted depending on the desired harmonic relation?

Btw using the same divider for both channels with a slight offset gives a sweet phasing effect that I haven't come across earlier, see attachment.

Edit Also tried it with short (12-bit) counters. Turned out pretty lame (no nice detune fx possible either), and the time savings are minimal, just 8t. So it's not worth continuing in that direction, I think.

Post's attachments

test.tap 110 b, 3 downloads since 2017-07-01 

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

72

Re: next gen engine ideas

Damn, seems it's the week of failed experiments for me. In the last days, I tried to implement a very ambitious concept, basically an improved, multi-threaded Squeeker type engine that will calculate optimal wavelength ahead of time, so it's possible to mix two waves with 50% duty with just one output. After trying for 3 days to get it stable, I finally got fed up and put it aside.
So then today I tried to mix 15 square wave channels. Works, but it's... not great. Hear for yourselves.

Post's attachments

test.tap 493 b, 3 downloads since 2017-07-12 

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

73 (edited by garvalf 2017-07-12 21:02:40)

Re: next gen engine ideas

I find this interesting nevertheless (I've only tried it from the fuse emulator). For the previous one, it reminds me of some SID effects, like the intro of Cybernoid: https://www.youtube.com/watch?v=bYQ9zUWVG4o (it's almost the same note!)