X16Community / vera-module

Versatile Embedded Retro Adapter
MIT License
13 stars 5 forks source link

Sawtooth and Triangle PSG waveforms should be XOR'd with the Width value #26

Open Yazwh0 opened 6 months ago

Yazwh0 commented 6 months ago

If we used the 6 bits in width to xor the 6bit value that feeds the signal_ value, we can let the users create sounds that are considerably more interesting.

As simple as something like this: (please note I dont know verilog, its simply xoring the value with the pulse_width.)

    wire [5:0] signal_saw      = cur_phase[16:11] ^ ~cur_pulsewidth[5:0];
    wire [5:0] signal_triangle = (cur_phase[16] ? ~cur_phase[15:10] : cur_phase[15:10]) ^ ~cur_pulsewidth[5:0];

This change is backward compatible as when using these waveforms width isn't used. If it is, the change will have an audio effect, but it will be similar so not to change the song. (eg the frequency isn't altered.)

For example xoring the sawtooth with 20 would create this waveform, which is considerably more interesting. There are a lot of possibilities for this change, which should be very cheap.

image

Yazwh0 commented 6 months ago

Its important to note implementations which set this value when its not used, would still sound very similar. Maybe not as clean, but similar. Like playing a midi track on different midi devices.

Yazwh0 commented 5 months ago

A cut of the official emulator with this in is available here: https://github.com/Yazwh0/x16-emulator/actions/runs/7493206859

gtr3qq commented 5 months ago

More waves the better! Although, how do you describe this modulation? Can it be achieved/recreated with analogue synth/OSC? What are the musical applications? From the waveform, it appears the modulation add a whole bunch of higher frequency content to the sideband. But I'm not sure if they're on scale of the fundamental. More to that, It looks like the fundamental is disappeared. Perhaps a sprectum gram?

gtr3qq commented 5 months ago

A cut of the official emulator with this in is available here: https://github.com/Yazwh0/x16-emulator/actions/runs/7493206859

I can't use keyboard with this version???😂 can you? even with -capture

Oh err, it's win64 release, let me get my Lubuntu boot up see if Linux release works

Yazwh0 commented 5 months ago

Sadly the action didn't pull the up to date version of the rom. So you can copy it from the most recent version of the official emulator.

Yazwh0 commented 5 months ago

More waves the better! Although, how do you describe this modulation? Can it be achieved/recreated with analogue synth/OSC? What are the musical applications? From the waveform, it appears the modulation add a whole bunch of higher frequency content to the sideband. But I'm not sure if they're on scale of the fundamental. More to that, It looks like the fundamental is disappeared. Perhaps a sprectum gram?

The change can be seen this in this spread sheet. Changing B2 from 0-63 will show you the 'before and after' waveform.

PSG_WidthExample.ods

gtr3qq commented 5 months ago

Sadly the action didn't pull the up to date version of the rom. So you can copy it from the most recent version of the official emulator.

Yep, pulling ROM.BIN (CRC32 E41AC606) from R46 release fixed the keyboard.

jburks commented 5 months ago

This change reduces the total LUT count by 15 compared to 0.3.3.

Attached is a VERA bitstream with this change made against fd78f273f2f05397f807115d08dedf5d267989cc.

diff --git a/fpga/source/audio/psg.v b/fpga/source/audio/psg.v
index ecdfaa3..d5dbcb0 100644
--- a/fpga/source/audio/psg.v
+++ b/fpga/source/audio/psg.v
@@ -160,8 +160,8 @@ module psg(
     // Signal generation
     //////////////////////////////////////////////////////////////////////////
     wire [5:0] signal_pw       = (cur_phase[16:10] > {1'b0, cur_pulsewidth}) ? 6'd0 : 6'd63;
-    wire [5:0] signal_saw      = cur_phase[16:11];
-    wire [5:0] signal_triangle = cur_phase[16] ? ~cur_phase[15:10] : cur_phase[15:10];
+    wire [5:0] signal_saw      = cur_phase[16:11] ^ ~cur_pulsewidth[5:0];
+    wire [5:0] signal_triangle = (cur_phase[16] ? ~cur_phase[15:10] : cur_phase[15:10]) ^ ~cur_pulsewidth[5:0];
     wire [5:0] signal_noise    = cur_noise;

     reg [5:0] signal;

vera_issue_26_test.zip

FavoritoHJS commented 5 months ago

extended a previous spreadsheet of mine to emulate this: fouriertest.ods

interestingly, all sawtooth waves created by this should sound identical, as they seem to have identical frequency content.

FavoritoHJS commented 5 months ago

triangles on the other hand... ooh boy this is gonna be interesting it seems like every bit in the xor value corresponds to a lump in frequency space so a xor value of 01h and 02h add some very high frequency content, with higher bits resulting in lower harmonics until you get to 20h, which is identical to an inverted 1Fh, a really weird waveform that should sound almost like a saw. (EDIT: it sounds like a square... EDIT2: albeit a high-passed one)

how many luts would adding a tildearrow sound unit-esque trisaw cost? As in, when the phase offset goes past a certain point, invert all output bits, otherwise do nothing. I wonder if some pulse logic can be reused.

gtr3qq commented 5 months ago

triangles on the other hand... ooh boy this is gonna be interesting it seems like every bit in the xor value corresponds to a lump in frequency space so a xor value of 01h and 02h add some very high frequency content, with higher bits resulting in lower harmonics until you get to 20h, which is identical to an inverted 1Fh, a really weird waveform that should sound almost like a saw. (EDIT: it sounds like a square... EDIT2: albeit a high-passed one)

how many luts would adding a tildearrow sound unit-esque trisaw cost? As in, when the phase offset goes past a certain point, invert all output bits, otherwise do nothing. I wonder if some pulse logic can be reused.

Welp, if you're on discord, there is this which corresponds with your view. https://discord.com/channels/547559626024157184/1168970882119647283/1197277852870135858

The triangle is intriguing, it produce a almost FM bell quality I feel.

Identical sidebands with each XOR value for SAWtooth yes, but it sounds slightly low-passed.

But the real mark for SAWTOOTH is that at some extreme value is inverts the wave which is rater useful for musik and ear-sweeteners.

Alas, it's my -2cent that it's worth the struggle solely for inverted sawtooth. But I don't seem to always in tune do I . (Pun indented)😂

FavoritoHJS commented 5 months ago

Welp, if you're on discord, there is this which corresponds with your view.

i wish... alas i have deleted discord from my life after the account denumbering incident, so i can't check stuff there.

\<rant>sad to see half of my world stuck inside a walled garden i cannot enter\</rant>

gtr3qq commented 5 months ago

Welp, if you're on discord, there is this which corresponds with your view.

i wish... alas i have deleted discord from my life after the account denumbering incident, so i can't check stuff there.

sad to see half of my world stuck inside a walled garden i cannot enter

Well, sad no more. I'll try to upload it YT or something.

gtr3qq commented 5 months ago

reference https://youtu.be/2a-X4lBqyjE x16emuspecal.7z.zip

LTVA1 commented 5 months ago

This looks interesting. I always kinda looked down at VERA because it was just simple waves on many channels sound source. XOR makes it a bit more interesting.

Is noise also affected by the XOR mask?

Yazwh0 commented 5 months ago

Is noise also affected by the XOR mask?

No, as random noise xored by anything is still random noise. It would be nice to use width for noise, but that isn't in scope of this request.

LTVA1 commented 5 months ago

Okay, I may open a suggestion about ANDing noise with inverted pulse signal so with pulse width 0 you get just noise and with width 0x20 you get basically AY pulse+noise signal

m00dawg commented 5 months ago

Mentioned in #29 a potential way to solve for existing compatibility by way of DCSEL. If we can be under the LUT budget with those additions, it would alleviate the compatibility concerns I think entirely.

FavoritoHJS commented 5 months ago

Okay, I may open a suggestion about ANDing noise with inverted pulse signal so with pulse width 0 you get just noise and with width 0x20 you get basically AY pulse+noise signal

how about ORing? that could help save some logic...

i'd check but yosys is especially broken this time and won't let me dummy out the video subsystems to keep compile times down to a reasonable level.

edit: i should really just give in and download whatever lattice suggests for this...

FavoritoHJS commented 5 months ago

also since the sawtooth isn't really affected by this... can something useful be salvaged from it? maybe by swapping it to the triangle waveform for the duration of the pulse wave?

LTVA1 commented 5 months ago

how about ORing? that could help save some logic...

ORing should produce the same sound without the need of inverting the pulse width value (if we still want not-altered sound with pulse width 0). I will test it in several hours

LTVA1 commented 5 months ago

Yeah, ORing gives the same sound, and no need to invert the pulse width

FavoritoHJS commented 5 months ago

Do keep in mind that 1/128th of the sound will be always on, even with the pulse width at its minimum value.

LTVA1 commented 5 months ago

Since VERA operates at rather low sample rate (that's the reason why PWM aliases like hell; yes, ~48 kHz is rather high sample rate but direct digital synthesis needs oversampling to sound good) I think it won't be noticeable until you use very low frequency...

Or you can just make a switch in DCSEL=whatever bank for the feature... But it certainly will bring LUT count up.

smaybius commented 1 month ago

What else could be done besides XOR, that involves the pulse width register? Other options could be blanking or inverting up to a certain point, the first one being directly homologous to the pulse width.