An audio (and #AUDIO) question

On the creation of AY or Beeper music, including the packages used to do so.
User avatar
SkoolKid
Manic Miner
Posts: 407
Joined: Wed Nov 15, 2017 3:07 pm

An audio (and #AUDIO) question

Post by SkoolKid »

Back in SkoolKit 8.7 I introduced the #AUDIO macro, which can be used to convert beeper sound effects and music into WAV files by executing Z80 machine code in a simulator and timing the intervals between speaker flips. (The #AUDIO macro was what motivated me to develop a Z80 instruction set simulator for SkoolKit in the first place, before I became obsessed with using it to --sim-load tapes instead. But that's besides the point.)

Anyway, I've noticed that #AUDIO works well some times and not others. For example, this conversion of the Manic Miner theme tune sounds OK to my ears:

https://skoolkit.ca/audio/manic-miner.mp3

But this conversion of the Fairlight theme tune sounds rather tinny, with high-pitched artifacts all over the place:

https://skoolkit.ca/audio/fairlight.mp3

Do any audio experts here know what might be going wrong in this conversion of the Fairlight tune, and how it could be fixed?

If need be, I will try to explain how the conversion is done, in case it's not obvious what the problem is. (And if anyone's interested, I'll explain how I used the #AUDIO macro to create the original WAV files from which these MP3 files are derived.)
SkoolKit - disassemble a game today
Pyskool - a remake of Skool Daze and Back to Skool
catmeows
Manic Miner
Posts: 718
Joined: Tue May 28, 2019 12:02 pm
Location: Prague

Re: An audio (and #AUDIO) question

Post by catmeows »

I don't read Python, but from brief examination of skoolkit, it seems to me that contention timing is just approximation in your emulator. Is that correct ?
IMHO, I would move this topic to emulator thread, there would be bigger chance to get answer.
Proud owner of Didaktik M
User avatar
SkoolKid
Manic Miner
Posts: 407
Joined: Wed Nov 15, 2017 3:07 pm

Re: An audio (and #AUDIO) question

Post by SkoolKid »

catmeows wrote: Sun Jun 18, 2023 9:45 pm I don't read Python, but from brief examination of skoolkit, it seems to me that contention timing is just approximation in your emulator. Is that correct ?
That is correct, but I don't think it's relevant to the question about the Fairlight tune, because the code for that runs entirely in uncontended memory.

(I'm also happy so far with the approximation of contended memory delays. For example, the converted tunes for Skool Daze and Back to Skool sound pretty good to me.)
SkoolKit - disassemble a game today
Pyskool - a remake of Skool Daze and Back to Skool
User avatar
deanysoft
Dizzy
Posts: 75
Joined: Sat Jun 18, 2022 10:35 pm

Re: An audio (and #AUDIO) question

Post by deanysoft »

I agree that it must be an accuracy of timing issue. The Manic Miner tune is a 'single note at once' tune (if you can call them notes) whereas Fairlight has the two-notes at once effect. In your tune there are some points where the tone is not distorted and it seems to be where only one note is playing - at 42.96 (according to Audacity) for instance. So a single note is emulated more or less fine, it's the dual note emulation it's having trouble with so I would think perhaps the output to the speaker is maybe not as accurate as it needs to be in order to clearly hear the two note effect. Maybe the drift in accuracy is adding the distortion. But I'm not expert at this kind of audio...

If you try the Wham music box (I'm sure other ones are available) you could create some test two-note tunes. You don't have to listen to the Wham tunes!
catmeows
Manic Miner
Posts: 718
Joined: Tue May 28, 2019 12:02 pm
Location: Prague

Re: An audio (and #AUDIO) question

Post by catmeows »

SkoolKid wrote: Sun Jun 18, 2023 9:54 pm That is correct, but I don't think it's relevant to the question about the Fairlight tune, because the code for that runs entirely in uncontended memory.

(I'm also happy so far with the approximation of contended memory delays. For example, the converted tunes for Skool Daze and Back to Skool sound pretty good to me.)
Well, port 254 is contended too (https://sinclair.wiki.zxnet.co.uk/wiki/Contended_I/O)

That said, Manic Miner's two channel is garbage that really don't care about timing too much, so maybe its harsh sound masks the issue.
But I don't know, I would try any WHAM tune, if there is similar issue. If not, then look into part where you mix bits into samples.
Sorry, I'm probably not helping here.
Proud owner of Didaktik M
User avatar
SkoolKid
Manic Miner
Posts: 407
Joined: Wed Nov 15, 2017 3:07 pm

Re: An audio (and #AUDIO) question

Post by SkoolKid »

I just took a look at the speaker flip delays produced by each tune routine (which you can do with the --audio option of SkoolKit's trace.py command), and what jumps out immediately is that Fairlight's is full of long sequences of very short delays interspersed between longer delays; for example:

Code: Select all

[48]*70, 96, [48]*71, 3456, 3504, [48]*70, 96, [48]*71, 3457, 3504, [48]*70...
This means 70 delays of 48 T-states each, a delay of 96 T-states, another 71 delays of 48 T-states each, a delay of 3456 T-states, and so on. The Manic Miner tune doesn't have anything like this.

So I'm guessing #AUDIO is just not handling these ultrasonic waves correctly. Maybe it should just pretend they're not there? I will have do some experiments...
SkoolKit - disassemble a game today
Pyskool - a remake of Skool Daze and Back to Skool
catmeows
Manic Miner
Posts: 718
Joined: Tue May 28, 2019 12:02 pm
Location: Prague

Re: An audio (and #AUDIO) question

Post by catmeows »

SkoolKid wrote: Sun Jun 18, 2023 10:40 pm Maybe it should just pretend they're not there? I will have do some experiments...
Good catch. Good luck :)
Proud owner of Didaktik M
catmeows
Manic Miner
Posts: 718
Joined: Tue May 28, 2019 12:02 pm
Location: Prague

Re: An audio (and #AUDIO) question

Post by catmeows »

Sorry, it is me again.
I think you really need to emulate beeper by outputing several volumes. It is not case of wham tunes, but some other routines try to emulate volume by shortening pulse. So I think you should add some transition period between the two states.
Like when beeper bit is off, go quickly to zero, if beeper bit is one, go quickly to full.
Proud owner of Didaktik M
User avatar
4thRock
Manic Miner
Posts: 415
Joined: Thu Nov 09, 2017 9:35 am
Location: Portugal

Re: An audio (and #AUDIO) question

Post by 4thRock »

I'd say it needs a much higher sample rate to fully capture whatever pulse modulation the sound engine is using.
After that, eventually apply a low pass filter to simulate the dampening characteristics of a physical speaker.
User avatar
SkoolKid
Manic Miner
Posts: 407
Joined: Wed Nov 15, 2017 3:07 pm

Re: An audio (and #AUDIO) question

Post by SkoolKid »

4thRock wrote: Mon Jun 19, 2023 10:32 am I'd say it needs a much higher sample rate to fully capture whatever pulse modulation the sound engine is using.
After that, eventually apply a low pass filter to simulate the dampening characteristics of a physical speaker.
Well, the effective sample rate of the #AUDIO macro is 3.5MHz, so I don't think it needs to be any higher. :) Now I've read a little more about such things, it looks like the problem lies in how I'm downsampling to 44.1KHz (the target sample rate of the WAV file). Wikipedia seems to suggest that a low-pass filter should be applied, as you say. Which I think is the proper way of "pretending the ultrasonic waves aren't there", as I put it earlier. I just need to find a low-pass filter algorithm I can implement efficiently in Python.
SkoolKit - disassemble a game today
Pyskool - a remake of Skool Daze and Back to Skool
User avatar
4thRock
Manic Miner
Posts: 415
Joined: Thu Nov 09, 2017 9:35 am
Location: Portugal

Re: An audio (and #AUDIO) question

Post by 4thRock »

Perhaps a dumb approach, like simply counting + and - pulses during fixed amounts of time would do. Just guessing really :D
User avatar
Lee Bee
Dynamite Dan
Posts: 1297
Joined: Sat Nov 16, 2019 11:01 pm
Location: Devon, England
Contact:

Re: An audio (and #AUDIO) question

Post by Lee Bee »

I haven't read the thread and this is just my quick opinion, but to me this just sounds like "clipping". Could it simply be too loud?
pobtastic
Drutt
Posts: 32
Joined: Fri May 29, 2020 8:21 pm
Location: United Kingdom

Re: An audio (and #AUDIO) question

Post by pobtastic »

Apologies for resurrecting this thread ... but mine also sounds terrible:

https://pobtastic.github.io/everyonesaw ... sound.html

My question is; is this an acceptable trace for the generation, or am I just suffering from the same issue discussed here?

Poke sets the music data to the music index pointer.

Code: Select all

trace.py --poke 0xB4E7,0x60 --poke 0xB4E8,0xB5 --start 0xB482 --stop 0xB493 --audio EveryonesaWally.z80
I mean... you can at least identify the tune as being correct, but it's really gravelly (if that's a word!)
User avatar
SkoolKid
Manic Miner
Posts: 407
Joined: Wed Nov 15, 2017 3:07 pm

Re: An audio (and #AUDIO) question

Post by SkoolKid »

pobtastic wrote: Thu Nov 02, 2023 11:11 am

Code: Select all

trace.py --poke 0xB4E7,0x60 --poke 0xB4E8,0xB5 --start 0xB482 --stop 0xB493 --audio EveryonesaWally.z80
I mean... you can at least identify the tune as being correct, but it's really gravelly (if that's a word!)
Are interrupts enabled in that snapshot? If so, but the tune is supposed to play with interrupts disabled, try running trace.py with interrupts effectively disabled:

Code: Select all

trace.py --no-interrupts --poke 0xB4E7,0x60 --poke 0xB4E8,0xB5 --start 0xB482 --stop 0xB493 --audio EveryonesaWally.z80
SkoolKit - disassemble a game today
Pyskool - a remake of Skool Daze and Back to Skool
pobtastic
Drutt
Posts: 32
Joined: Fri May 29, 2020 8:21 pm
Location: United Kingdom

Re: An audio (and #AUDIO) question

Post by pobtastic »

Oh nice! Ah, I'm using 8.10 - so I think this is a slightly later addition. https://github.com/skoolkid/skoolkit/co ... a67b0a59c8

I just assumed if I didn't use

Code: Select all

--interrupts
then they'd default to being disabled. Lemme give it a go with the dev version, thank you.
pobtastic
Drutt
Posts: 32
Joined: Fri May 29, 2020 8:21 pm
Location: United Kingdom

Re: An audio (and #AUDIO) question

Post by pobtastic »

Yeah, appears to generate the same output.

Doesn't matter, it's a nice-to-have - but it doesn't need to be identical.

edit... BTW ... just to say ...

Code: Select all

$ ~/Workspace/skoolkit/trace.py --no-interrupts --poke 0xB4E7,0x60 --poke 0xB4E8,0xB5 --start 0xB482 --stop 0xB493 --audio --stats EveryonesaWally.z80
Stopped at $B493
Z80 execution time: 245424702 T-states (70.121s)
Instructions executed: 37174154
Simulation time: 26.688s (x2.63)
Sound duration: 245399684 T-states (70.114s)
Delays: [4501, 4559]*116, 4501, 25924, etc etc etc...
Skoolkit is just simply incredible!
User avatar
SkoolKid
Manic Miner
Posts: 407
Joined: Wed Nov 15, 2017 3:07 pm

Re: An audio (and #AUDIO) question

Post by SkoolKid »

pobtastic wrote: Thu Nov 02, 2023 11:36 am Skoolkit is just simply incredible!
OK, in return for those kind words, I'll point out that you're setting flags=$01 in your #AUDIO macro, which simulates memory contention:

https://github.com/pobtastic/everyonesa ... /sound.ref

Don't do that! Try this instead:

Code: Select all

#AUDIO(tune.wav)(#INCLUDE(ThemeTune))
SkoolKit - disassemble a game today
Pyskool - a remake of Skool Daze and Back to Skool
pobtastic
Drutt
Posts: 32
Joined: Fri May 29, 2020 8:21 pm
Location: United Kingdom

Re: An audio (and #AUDIO) question

Post by pobtastic »

I have to confess, I did copy that line almost directly from here... https://github.com/skoolkid/backtoskool ... nd.ref#L10 without really giving any thought to what the flags did.

Apologies, I should have RTFM! :lol:

...and like magic, it now sounds amazing! Thank you so so much!
TheMartian
Microbot
Posts: 100
Joined: Wed Feb 03, 2021 5:18 am

Re: An audio (and #AUDIO) question

Post by TheMartian »

SkoolKid wrote: Sun Jun 18, 2023 9:02 pm But this conversion of the Fairlight theme tune sounds rather tinny, with high-pitched artifacts all over the place:

https://skoolkit.ca/audio/fairlight.mp3
This sounds exactly like SpecIde did before I applied a moving average filter to the audio outputs.
User avatar
SkoolKid
Manic Miner
Posts: 407
Joined: Wed Nov 15, 2017 3:07 pm

Re: An audio (and #AUDIO) question

Post by SkoolKid »

TheMartian wrote: Fri Nov 03, 2023 5:02 pm This sounds exactly like SpecIde did before I applied a moving average filter to the audio outputs.
Interesting! What signal data do you apply the moving average filter to?

With the #AUDIO macro, the raw signal data is a sequence of delays between speaker flips. Applying a moving average filter to that data doesn't improve the sound at all. Then there is the amplitude data written to the WAV file. Applying a moving average filter to that data doesn't improve the sound either - but that might be because the delays-to-amplitudes algorithm I'm using is crap.
SkoolKit - disassemble a game today
Pyskool - a remake of Skool Daze and Back to Skool
TheMartian
Microbot
Posts: 100
Joined: Wed Feb 03, 2021 5:18 am

Re: An audio (and #AUDIO) question

Post by TheMartian »

SkoolKid wrote: Fri Nov 03, 2023 6:14 pm Interesting! What signal data do you apply the moving average filter to?

With the #AUDIO macro, the raw signal data is a sequence of delays between speaker flips. Applying a moving average filter to that data doesn't improve the sound at all. Then there is the amplitude data written to the WAV file. Applying a moving average filter to that data doesn't improve the sound either - but that might be because the delays-to-amplitudes algorithm I'm using is crap.
Well, I just sample the ULA bits regularly (at 1,75MHz, half the Speccy CPU clock, uncontended) and store that in an array of size 128 (at position index modulo 128). Whenever I need an actual audio sample at 44100Hz (each 158,73 cycles, roughly) I average the data and that's the sample. The longer the array (say, 256 instead of 128), the lower the frequency cut.

I guess if you figure out a fixed sample step and depending on the delays you've got you just get those samples, you can average them for each sample at 44100Hz.

My code is public, if you want to check: https://github.com/MartianGirl/SpecIde - check src/ULA.cc, the beeper() and sample() functions, and src/Spectrum.cc in clock(), line 368 and next.
User avatar
SkoolKid
Manic Miner
Posts: 407
Joined: Wed Nov 15, 2017 3:07 pm

Re: An audio (and #AUDIO) question

Post by SkoolKid »

TheMartian wrote: Fri Nov 03, 2023 7:11 pm I guess if you figure out a fixed sample step and depending on the delays you've got you just get those samples, you can average them for each sample at 44100Hz.
https://skoolkit.ca/audio/fairlight-filtered.mp3

:dance

That sounds so much better now. Thanks a million!
SkoolKit - disassemble a game today
Pyskool - a remake of Skool Daze and Back to Skool
TheMartian
Microbot
Posts: 100
Joined: Wed Feb 03, 2021 5:18 am

Re: An audio (and #AUDIO) question

Post by TheMartian »

Awesome!!! :dance
User avatar
SkoolKid
Manic Miner
Posts: 407
Joined: Wed Nov 15, 2017 3:07 pm

Re: An audio (and #AUDIO) question

Post by SkoolKid »

And in case anyone's wondering, I've squeezed moving average filter support for the #AUDIO macro into SkoolKit 9.0 (due very soon):

https://github.com/skoolkid/skoolkit/co ... bb5465c192
SkoolKit - disassemble a game today
Pyskool - a remake of Skool Daze and Back to Skool
TheMartian
Microbot
Posts: 100
Joined: Wed Feb 03, 2021 5:18 am

Re: An audio (and #AUDIO) question

Post by TheMartian »

I'm so glad it worked.

I believe the cause for this effect resides in Nyquist theorem: You need the signal to be frequency-limited previous to a sampling process (the creation of the WAV file is a sampling at 44100). If the signal is not bound in frequency to half the sampling frequency there'll be aliasing.

The raw emulated ULA signal is perfectly square (it goes from 1 to 0 immediately) so it needs to be smoothed before sampling.

I guess a LP filter of any kind would do the same effect as the MA, but I didn't remember how to code that, and the MA is really simple...

The new WAV sounds great :smile: Congratulations.
Post Reply