Thanks! I had initially planned on implementing this, but ultimately abandoned the idea, mostly because of my lack of experience in coding such a system. At the current stage, it would be quite tricky to add, because there's just a few hundred bytes of memory left. And there's actually a few other features that I still want to implement (advanced live mode, better copy/paste/clone support), so I'd rather spend the remaining bytes on this. I might consider it again at some point, but at the moment I'd rather try to convince the TiLP guys to try and add Android support, which would probably solve the problem for many people as well.

Btw, a call for action to everyone: Please do test the latest beta versions from github. There are a couple of nasty issues which I need to sort out before I can progress further. So far I've had no luck with these, so any input on them is highly appreciated.

Talkin' bout da tracker at Revision last weekend: https://www.youtube.com/watch?v=7UgSDAkXAJw
Rather technical, with a lot of uhhm and ehhm, and a failed demonstration of the QED68 sound routine at the end.

3

(60 replies, posted in Sinclair)

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.

Well, generating a huge number of pin pulse channels is not a problem at least, thanks to Jan Deak's buffer method. I wonder though if it's possible to come up with an elegant algorithm that uses only one oscillator and derives the detuned copies from that, like the original SuperSaw supposedly does. For example, a simple 8-bit counter that increments once per loop iteration could already be enough to generate two derivatives (one added to main osc, one subtracted).

Interesting technique! How does it work exactly? Do you think it would be viable for a native implementation on Spectrum etc?

6

(60 replies, posted in Sinclair)

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.

7

(60 replies, posted in Sinclair)

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.

I think some MIDI solution would be preferable because of its potential impact. Would it be possible to ditch the Arduino MIDI shield and just decode the MIDI messages directly on the Arduino, using one of the digi ports? It would cause some additional load on the CPU of course, but on the other hand there's no need to load sequence/pattern data any more. As far as instruments go, yes, they could be pre-defined patches, but the engine should also make best use of the available standard Control Change messages, which could be linked to settings of duty, vibrato, etc.

Impressive! Never managed to port this engine to TI because of the interrupts. But I guess the variable timer interrupts on the Arduino come in very handy in that case.

So, what's next, any plans for a custom Arduino engine written in C?

10

(12 replies, posted in Other Platforms)

Was just reading about this guy's troubles, so a software issue seems quite possible.

Perhaps it's easier to disable auto-reset until you've found the culprit?

11

(4 replies, posted in Sinclair)

Cheers Tufty wink Both channels are identical, so yes, you can use two SID voices at once. Click drums are synthesized. The drum synth is less advanced than in Phaser1 or Phaser2, but nevertheless you can pass an 8-bit parameter to change their sound. On kicks, you can set the starting pitch, and on click noise, you can select one of two fixed pitches, and set the volume. For really advanced trickery, a completely different drum synth could be swapped in via the "arbitrary code execution" feature, which allows you to literally change any aspect of the engine at runtime. Furthermore, you can of course fake drums via table fx - noise combines nicely with volume envelopes, too, for example.

12

(7 replies, posted in Other Platforms)

Wow Shiru, looks like you're on a roll!

Since Arduino 1-bit seems all the rage now, I thought I'd give the avra+avrdude combo a try. Works like a charm, successfully produced a beep in asm!

Indeed, 16 MHz is a lot, especially considering the instructions are also super-fast. Guess I'll have to get used to writing purposefully slow asm code. Or just write complex enough routines, heh. Well, for now I'll leave things at "yay, my toolchain works" but next time I get bored with my other projects I might actually go and try writing a dedicated routine for this thing.

Edit: Wow, I just found out that ATmega has a fixed-length, 2-cycle MULtiply instruction. This should make it possible to implement stuff like 1-bit Phase distortion, perhaps even FM.

Thanks! Looks like even someone totally inept at soldering like me can construct this.

14

(7 replies, posted in Other Platforms)

Awesome! Listening to the demo tune right now, and I can confirm there's no noticable artifact/carrier noise on my setup.

Well, would be great if this gets some exposition on the Arduino forums. If there's enough interest, we might even consider opening a special Arduino sub-board on here.

15

(4 replies, posted in Sinclair)

esoteric music plays... Imagine... a beeper engine that can play almost any sound ever played by any beeper engine. An engine that transcends the boundaries between data and code by enabling you to modify any part of the player at runtime. An engine that will revolutionize the way we make beeper mu-record scratch

Ok guys, let's cut the crap wink Here's my latest engine. It picks up where wtbeep left off, and combines the modular concept of it with the simplified volume generation technique I posted for the saw wave demo here. It's insanely powerful, but unfortunately, composing music for it will also drive you insane, as there's no editor available and the data format is rather complex. In theory, the latest MDAL should be able to support the engine, but I need to implement mixing of strings and numeric values before it really makes sense to try.

Anyway, have a quote from Uncle Readme.

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

source: https://github.com/utz82/ZX-Spectrum-1- … aster/bm-1
direct dl: https://github.com/utz82/ZX-Spectrum-1- … p?raw=true


This will be more or less my last engine for the ZX beeper, until a some fundamentally new techniques are discovered. I still have two ideas I want to put into practise, but these will be rather simple (one is an engine with vibrato support, and one is applying the volume technique from BM-1 to wavetables, which will save a huge amount of code compared to the multi-core technique). Not sure when I'll do those, if somebody else wants to pick up these ideas in the meantime, that's fine with me. No worries though, I have no intentions of abandoning the Spectrum, but I have some other unfinished projects that I want to focus on in the coming months. Stay tuned.

Edit: Added an example patch for PFM sound.

16

(18 replies, posted in Other Platforms)

Alright, sucessfully uploaded garvalf's hex file with avrdude. The ELF doesn't run however, avrdude claims it's not valid. So I guess it's some intermediate thingy that's not meant to be uploaded. Well, no problem for now.

Good to see that the avr-gcc is reasonably efficient. Also, I still think it's very nice that you get annotated output with avr-objdump.

Still not sure if I want to install the latest IDE, especially not alongside the older install. If it were all contained in a standalone Java app then sure, but afaik it installs a ton of other stuff, namely all the avr tools. And I'm afraid checkinstall won't do the trick on this one.

I'm sorry but I don't have any octode demo tunes to offer. Have several snippets laying around but never managed to actually complete a song with it yikes

So, guys, excuse my absolute electronics ignorance, but what would be the most reasonable approach to adding a line-out to this thing? Right now I have a PC speaker attached like garvalf, with some resistor thrown in for good measure.

17

(18 replies, posted in Other Platforms)

I feel your pain, man. Arduino documentation is good but only as long as you're going to do things their way.

Anyway, dug out my Uno clone today and tried to run Octode, but as expected the ELF compiled with 1.0.5 IDE doesn't work. Could you share your ELF, so I can try to upload it directly?

18

(18 replies, posted in Other Platforms)

Well, you have a point. I'll think about it more... perhaps write some simple tool that will convert AVRA source to Arduino syntax.

Anyway, I tried compiling arduino_octode, but I was getting some errors. I think it's because I have a very outdated version (1.0.5, thanks Debian) - it doesn't like PROGMEM and NULL. I got it to compile with defining NULL as 0 and PROGMEM as nothing, but that is not the correct way to do it afaik. I should probably replace the Debian version with a newer one, but given that the sources are like 90 MB I'm not too inclined to do it right now, as it would probably take half a day to compile them on my machine.

Anyway, I was able to extract the resulting ELF file and disassemble it. avr-objdump outputs a pretty nice, commented listing, so I'd say give it a try. Or, if you're having problems with it, send me the ELF files (ctrl-f arduino_octode.cpp.elf) and I'll send you back the asm listings.

19

(18 replies, posted in Other Platforms)

Wouldn't it be possible to link Arduino C code against a pre-compiled library? Then such a library could be written in asm. That was actually what I was intending to do with the Z80 emulation.

20

(18 replies, posted in Other Platforms)

Wow, I wouldn't have thought that it's possible to pull this off in C at all. I personally have no interest in programming this thing in C considering the beauty of the AVR m'code instruction set, but still, nice to see it works and is efficient enough.

Regarding the point you mentioned about the while loop, have you checked how the compiler implements this? It should be possible to get the resulting asm code somehow. Afaik the Arduino thing runs on AVR-GCC, so I suppose you could run the code directly through AVR-GCC with -S switch to get the asm output.

I think your stability issues will be related to your PC's USB port. Many PCs have their USB ports improperly configured and/or use crap controllers, which causes them to deliver unstable/out-of-spec current. Since you say that things are fine when running the board off external power, I'm pretty sure that's what's happening here.

Ah, excellent. I've been using my own (C++) lib for quick prototyping of XM converters since a while so I have no acute need for this, but mine is very badly designed so I can't publish it as a stand-alone library. So it's nice to have a clean and well-designed backup plan.

I'm surprised it's so slow, though. I mean Python is not exactly fast, but it shouldn't take that long. I took the liberty of running the script through cProfile and this is what I got:

         5450 function calls in 7.201 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.021    0.021    7.201    7.201 convert_octode.py:3(<module>)
        1    0.000    0.000    0.000    0.000 genericpath.py:55(getsize)
        1    7.138    7.138    7.138    7.138 xmlib.py:10(XM)
        4    0.000    0.000    0.000    0.000 xmlib.py:133(get_order)
        2    0.000    0.000    0.000    0.000 xmlib.py:140(get_pattern_length)
     1024    0.002    0.000    0.002    0.000 xmlib.py:148(get_note)
     1024    0.002    0.000    0.002    0.000 xmlib.py:153(get_instrument)
     1024    0.002    0.000    0.002    0.000 xmlib.py:158(get_volume)
     1040    0.002    0.000    0.002    0.000 xmlib.py:163(get_effect)
     1025    0.004    0.000    0.004    0.000 xmlib.py:168(get_parameter)
       15    0.000    0.000    0.000    0.000 xmlib.py:26(read_word)
        3    0.000    0.000    0.000    0.000 xmlib.py:29(read_dword)
        1    0.029    0.029    0.029    0.029 xmlib.py:32(load)
        1    0.000    0.000    7.138    7.138 xmlib.py:4(<module>)
        1    0.000    0.000    0.000    0.000 {len}
        2    0.000    0.000    0.000    0.000 {method 'append' of 'array.array' objects}
        1    0.000    0.000    0.000    0.000 {method 'close' of 'file' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.000    0.000    0.000    0.000 {method 'fromfile' of 'array.array' objects}
        1    0.000    0.000    0.000    0.000 {open}
        1    0.000    0.000    0.000    0.000 {posix.stat}
      276    0.001    0.000    0.001    0.000 {range}

I think the main bottleneck happens with setting up the arrays on constructing XM class object. I tried with XMs of varying complexity, there is almost no change in execution time. So the conversion functions aren't the problem, in any case. Not sure how that can be rectified. One could of course read the song parameters first and only set up the necessary amount of arrays afterwards, but I have a feeling that that doesn't tackle the problem at its root.

Hmm, this looks interesting, especially the last answer. I'm not a Python coder at all though.

22

(5 replies, posted in Sinclair)

I've actually done some AVR code before, it is indeed a very easy chip to code on. I also have a SeinSmart Uno (Chinese Arduino knock-off) laying around somewhere, and I have an asm programming toolchain installed (Arduino IDE is indeed useless for that), though I can't remember what the actual commands for it were.

In any case, I think Z80 emulation on a 16MHz AVR would be tricky, but possible, albeit not without cutting some corners. I think main challenges will be instruction decoding, and dealing with the AVR's big-endianness. I would suggest:

- Emulation of 4 MHz clock speed instead of 3.5, easier to emulate the correct cycle count like that
- Cut all interrupt-related stuff. This would break SpecialFX and Savage, but I think the benefits far outweigh this. Actual interrupts should be handled outside of the Z80 emulation.
- No R register auto-update.
- No emulation of 5,H,3,N flags and MEMPTR.
- DAA replaced with NOP (would break wtbeep, but oh well)

In any case, I would be willing to work on an AVR Z80 emulation. However, I currently have several other ongoing projects that I want to finish first (MDAL, mainly - made some good progress last month but there's still a few major features missing, such as multi-track sequences, "virtual" sequences, and sample support).

23

(5 replies, posted in Sinclair)

Ok Shiru, you've convinced me of the benefits of a card that run standard beeper engines. Well, maybe Arduino is not such a good idea, after all - using a large Ardunio as the base of this might drive up the costs too much. I mean how much would people be willing to spend on this? 30€? Maybe 50 if it includes a joystick interface?

Either way I know very little about these things, so I'm afraid I can't be of much help.

(discussion split off from the Sleizsa Trio thread)

About a beeper card, would it perhaps make sense to make it Atmega based? I think it might help the popularity of such a device if it could be build from "standard household appliances", eg. Arduino. On the other hand, a Z80-based card could be made in a way that it would run Spectrum beeper engines without adaptation, which would be a big bonus, too. Not sure what's the better approach.

Been a while since I coded something on Fairchild F8... well, here's a new sound routine for the Channel F (aka VES, Grandstand, Saba Videoplay). Sleizsa Trio features 3 tone channels (one of which can play noise instead of tone), globally configurable duty cycles, and 2 interrupting click drums. It uses a mixing algorithm based on Zilogat0r's Squeeker engine for the ZX beeper, which does a somewhat better job with the Channel F's crude sound generator than Sleizsa Duo's pulse interleaving method.

Demo tune: https://soundcloud.com/irrlicht-project … -channel-f
Download: https://github.com/utz82/SleizsaTrio/releases/latest (XM converter included)
Github repo: https://github.com/utz82/SleizsaTrio