101

(135 replies, posted in Sinclair)

Neat idea, don't think we've used that anywhere yet.

I wonder if it could be pushed even further. Like, instead of every frame, add the offset at a variable rate. That could perhaps turn into a sort of 1-bit FM, without the use of PCM emulation trickery. (Sorry for hijacking your idea immediately, but I recently tried to implement actual FM again, and came to the same conclusion as last time: It's possible to do the necessary calculations fast enough, but the output is too noisy for reasons not entirely clear to me.)

Thanks  for sharing.

Does your tool do spectrograms as well? Those sometimes look super interesting with 1-bit music,

103

(2 replies, posted in Sinclair)

TOO QUIET! big_smile big_smile big_smile

104

(128 replies, posted in Sinclair)

Shiru wrote:
2.   7.18   Synthetic Heartbeat by Ataritufty ^ 1bit Forum
3.   7.17   Noise In My Head by Shiru

That's insane. Btw, what's "iqm" supposed to be?

105

(128 replies, posted in Sinclair)

Ha, I thought Tufty's unce track was going to win, since it was so well received at the party.

Cosmic Puppy is indeed an excellent track. AER really re-invented himself with that. Though I think Noise In My Head is the best in terms of composition. Stellar work on the drums and those Shiru™ delays. Both your tracks are Earth Shaker EX, right Shiru?

Anyway, I think this was the strongest compo we've had in years. Good times for beeper.

106

(4 replies, posted in Other Platforms)

I tried to push some 1-bit techniques on the Vic some years ago, but didn't get very far. 656x sound is very weird, and it seems to me there's a large number of quirks and oddities that are completely undocumented.

So, until we can come up with something better, how about some classic out-of-the-box, non-1bit VIC bleeps instead: https://www.youtube.com/watch?v=-rRPMrTR7QY

107

(4 replies, posted in Sinclair)

Thanks! The bad news is that eliminating row noise in this way is tedious as hell. 0/10, would not do it again. Even zbmod with its 20something cloned cores was more fun to write.

Btw, forgot to mention, the engine breaks Fuse. A work-around is to go "Media"->"Tape"->"Clear" after starting the tune.

As I was looking for an alternative, I surveyed a few other emulators running on Linux on their beeper capabilities. Results were mixed.

  • Mame: Still the same. Passable beeper emulation, but not as good as Fuse's. Also, no auto-load capabilities.

  • jsspeccy: Very noisy beeper emulation. Not usable.

  • ZEsarUX: Errr, no. Just no. With "real beeper" mode enabled, the sound is muffled as if it came from under a pillow. Turn "real" mode off and you're left with a screeching, grinding noise that bears 0 resemblence to the actual sound.

  • Xpeccy: I remember this having rather bad beeper emulation, but apparently it's improved quite a lot. It's a bit too clean, but definitely usable. I would consider switching (also because of the fantastic debugger), but unfortunately graphics render with extreme tearing. Also, no key combo to exit the program AND ignoring SIGTERM? Come on.

So, all in all, let's hope Fuse will fix this problem. Submitted a bug report, but no response yet.

108

(4 replies, posted in Sinclair)

Ok, one more. This will be the last one for now. I've got some more ideas, but my motivation batteries are a bit exhausted for the time being. Also I do want to work on some other projects in the coming weeks.

Anyway, tftone is basically Tritone (Digi) without transition noise. No special tricks here, just plain and boring loop unrolling. Runs a bit slower than the original Tritone (216t loop), but row length can be controlled up to ¼ tick precision. So yep, it can go really fast.

Due to the big spaghetti mess there may be some bugs hiding here and there. Ultimately I would also like to get the synth loop a bit faster, 216t is still pretty noisy. I think at least 208t should be doable.

I did discover one neat trick. Probably nothing new to some of you, but. I normally like stack-based loaders, not just because they're fast, but also because you can do POP AF and have individually set Z,C,S and P flags for a quick&dirty compression scheme. With this engine however, stack-based loading wasn't feasible. So I found that actually, something functionally equivalent to POP AF can be achived with

  ld a,(hl)     ; or whatever the data pointer is
  or a          ; check for Z
  jr z,...        ; end of pattern or whatever
  sla a

Now the last one is where the magic happens. If bit 7 was set, Carry is now flagged. If bit 6 was set, Sign is flagged. SLA also flags Parity, which means we can turn that on or off individually as well, just need to pay attention to bit 6 and possibly flip another bit so the initial value is not 0 when we don't intend it to be.

Anyway. so much for that. Code's on my github repo as usual. Sorry for the crappy demo tune. Just wanted something fast to demonstrate that it does sound (relatively) clean, but of course that's really tedious to type up in asm. And this is actually speed 4, so it can go even faster.

109

(128 replies, posted in Sinclair)

Thanks. Planning to submit but don't have anything yet.

Thanks for the report, fixed. Also fixed a bug with pindsvin's drum timing.

I hope the new data format won't be too much trouble. In the worst case you could just write every row, I guess, though it certainly would be nice to have a proper dictionary of unique rows.

Ho ho ho! 'tis the season! What season? The season for new beeper engines of course.


Pulsatilla

2 squeeker channels + 2 pulse-interleaving channels, all with full duty control. Squeeker channels can be combined into a single Phaser-like channel. PuInt channels are asynchronous, channel 4 is about half as loud as channel 3. Channel 1 has a noise mode, and channel 4 has a duty sweep mode. Phase can be controlled precisely for advanced volume/timbre tricks. Also includes synthesized interrupting click drums. Standard 224t loop, engine size 418 bytes.


Pindsvin

2 squeeker channels with duty control + 3 PFM channels with volume control. Squeeker channels can be combined into a single Phaser-like channel. Also includes interrupting PWM drums with volume control. 7-bit tempo control at half-tick resolution, 292t loop, engine size 330 bytes.


nanobeep3

Yay, finally beat my own record after 7 years. A complete beeper engine in 54 bytes, this time with proper pulse interleaving sound. 8-bit dividers (acceptable tuning in the range of C-2 - B-5, lower notes can be reached but may be out of tune), and a compact split-channel data layout. No click drum, but kicks are easy to simulate in a reasonable amout of data thanks to per-row tempo control. Some additional making-of-ish ramblings here.


No tracker support for now. Source code is available in The Holy Github repo, as usual.

Whaa, what a crazy machine is this? Is it like a miniature BK or something?

Hotdamn, some very nice trickery going on in this one. And kickass music, as usual. Thanks a ton for publishing the source, I think I'll have some studying to do.

114

(11 replies, posted in Other Platforms)

Hmm, that's going to be a bit tricky. Unfortunately the disassembly is barely commented so it's kinda hard to tell what the code does by just quickly looking at it. Basically what you'd need to do is this: Find out which part makes up the main sound loop (I'm guessing lines 90-204). Count the cycles for this code. Calculate how many times you need to loop to get a 50 Hz rate. Set up a loop counter based on that. Afaict the AF' register is unused, so you could use A' to count, ie. before line 90 you set up A' with the correct value. Then just before line 204 you decrement A and then do a JP NZ instead of the JP. The fall-through (Z condition) should then jump to the former interrupt code.

115

(3 replies, posted in Other Platforms)

Looking great! Is that a VHS case you're using there?

I'm not a hardware guy so my understanding of the audio circuit is minimal, but I'm guessing the filter should give a nice, bassy sound?

Regarding which audio engine to use as a showcase, the best option would be to write a new one, of course big_smile So we could make proper use of those 8 MHz. I would actually be up for coding something, but I'm going to be pretty busy for the next month and a half, so I can't promise any quick results. That said, please post details about how to address the beeper in code, so I can start scheming.

In the meantime, I would recommend to go with one of the Squeeker-type engines. Shiru's Squat (available in his 1tracker) is probably a good starting point. The advantage here is that Squeeker-type engines use only one output command per sound loop, so you don't need to be too concerned about keeping multiple outputs properly aligned. Basically just stuff a bunch of wait states somewhere into the sound loop to adjust for the higher clock speed. Pretty much every newer ZX Spectrum beeper engine has the cycles for the sound loop counted out in the source code, so you just need to find that and multiply by 8/3.5 to get the number of cycles you need for your machine.

Hi Andy, welcome aboard. We aren't the most busy place on the internet, so replies might be a bit slow to come in at times. Please don't let the deter you from posting though, I'm definitely interested in your project!

117

(8 replies, posted in Sinclair)

Would be great if he got a massive bout of nostalgia and caught the 1-bit bug once more after listening to your album, hehehehe!

118

(135 replies, posted in Sinclair)

I've been toying with a very promising new engine design that makes it possible to use computation-heavy effects, while also eliminating row transition noise. I don't have time to develop this into a full engine at the moment, but I thought I'd share the idea in case anybody else wants to play with it.

The design revolves around using a crude scheduler to implement basic multi-threading. Within every iteration of the sound loop, the scheduler allots a fixed portion of the available cpu time to the main thread, which updates frequency counters and calculates the output value(s) for the next iteration. The rest is allotted to a variable pool of secondary threads, which run consecutively in between each main thread run. In other words, our sound loop consists of two parts - the first part is always the same and runs all those updates that are required on each sound loop iteration. The second part runs varying tasks that do not require fast updates, for example counting length, computing some effect, or reading in note data.

The scheduler is implemented by pointing the stack pointer to the music data, and then simply RETurning after the main thread. To keep the music data size manageable, we need to implement sequence loops and subroutines as abstract operations running as secondary threads. Ideally we'd do nested subroutines, however that's a bit expensive to compute and in some cases one could probably get away without nesting. No nesting basically mirrors the sequence/pattern approach we normally use. The following example would play two notes over and over again:

sequence
    dw set_note_ch1, some_note
    dw init_loop, #3fe     ; set note length
    dw jump_sub, delay
    dw set_note_ch1, some_other_note
    dw init_loop, #3fe     ; set note length
    dw jump_sub, delay
    dw jump_seq, sequence

delay
    dw do_nothing
    dw loop, delay
    dw return

Now, that may seem like a rather inefficient way to just do

seq
    dw pattern
    dw seq_end
    dw seq

pattern
    dw length, note
    dw length, other_note
    db ptn_end

Perhaps it makes more sense to pick a certain number of threads, and think of the time they will take as your refresh rate/tick length, eg.

    ...
    dw set_note, note
    dw init_loop, #80         ; 0x80 * 0x10 + 3 = 0x803 loops/ca. 8 ticks (so we can get away with just an 8-bit length counter)
    dw jump_sub, fx01
    dw set_note, other_note
    dw init_loop, #40
    dw jump_sub, fx02
    ...

fx01
    dw calculate_expensive_fx_part1
    dw calculate_expensive_fx_part2
    dw do_something_else
    dw jump_sub, delay11
    dw loop, l1     ; 16 

fx02
    dw calculate_other_expensive_fx_part1
    dw calculate_other_expensive_fx_part2
    dw calculate_other_expensive_fx_part3
    dw calculate_other_expensive_fx_part4
    dw do_something_else
    dw jump_sub, delay9
    dw loop, l1

delay11
    dw do_nothing
    dw do_nothing
delay9
    dw do_nothing
    dw do_nothing
    dw do_nothing
    dw do_nothing
    dw do_nothing
    dw do_nothing
    dw do_nothing
    dw do_nothing
    dw return

Still expensive in terms of data size, but essentially we can now run things that we used to run in the outer sound loop (so, every 256*innter_loop_length t) at a much faster rate without affecting sound. This allows us to do stuff like fast&precise slides/vibrato and all sorts of variable-rate modulation effects. Also with recursive subroutines, you could actually have subroutines that generate subroutines... I think one could go pretty wild with this.

https://www.youtube.com/watch?v=w9DfLcCqpnU

Lol, we actually won the oldskool compo at Deadline with this. Found out only once it was too late that the boys are screwing around with the vblank irq, which affects the timing of the music, but oh well... Own sound engine with 3 modes: standard shift register sound, software bass, software bass with crude duty control. Also sorry, no greetz.

Hey, where'd the rest of the post go? Don't worry about being off-topic, there's no rule against OT on 1-bit forum, hehe.
In any case, that sounds lovely.

121

(11 replies, posted in Other Platforms)

Hahaha nice, I love it!

Yesss, I love these shed videos! The thought that there's someone on the complete opposite side of the planet listening to 1-bit sounds in a shed out in the countryside is just fantastic. If you don't mind asking, whereabouts in AU are you based?

123

(11 replies, posted in Other Platforms)

Yay, sounds great indeed! Almost cleaner than on Spectrum. I wonder if it's like this on actual hardware.
What's the process for loading stuff up in MESS?

124

(11 replies, posted in Other Platforms)

I've heard about this machine before! Fat chance I'll ever see one here in good ol Europe though yikes

ArcadeDB claims that sound emulation in MAME is "good", at least for the base 16k machine (though I've found that to not always be true for other machines), so it might well worth to give it a try. I've dabbled with MAME quite a bit, so If you were to upload a .tap or .dat or whatever the go-to emulator format is, I could try to work out how to load it.

125

(164 replies, posted in Sinclair)

Thanks! I can confirm it works. Interesting to see this in action, in any case. I'll have to play more with it to see how I'll use it in practise. No time right now but winter is coming...

Edit: Just as I was writing the above, I thought of something. I recently composed a somewhat longer track directly in asm. As I went along, I found myself relying more and more on macros, up to a point where almost the entire track was completely macro-ized. Now, I could definitely imagine using reference blocks in a similar fashion, ie. create a "fake" kick or whatever, give that a name, then improve it later on and use Ctrl-Shift-P to update all the occurances.

However, there are two problems with this. First of all, I've been using a lot of parametric macros as well, eg. for a variable starting pitch on a kick. This could work with the block ref system if a ref update would (optionally) ignore all data in the child blocks that do not match the parent.

The second problem is more serious. Basically, I wouldn't want to create a seperate block for each kick in the track - that would completely defeat the main purpose that blocks currently serve, which is quick navigation and easy copy/pasting of song sections. So basically this would require ref blocks to be a separate thing from the current block sections.

Well, just throwing out some ideas here, obviously nothing really thought out.