ENTERPRISE KLUB
2019. május 25., 1055 Budapest, Nyugati tér 9. 14-19 óráig
Részletek
Welcome, Guest. Please login or register.


Author Topic: Pulse Width Modulation on Dave (Read 1262 times)

Offline ssr86

  • EP user
  • *
  • Posts: 359
  • Country: pl
  • OS:
  • Windows NT 6.2 Windows NT 6.2
  • Browser:
  • Firefox 49.0 Firefox 49.0
    • View Profile
Pulse Width Modulation on Dave
« on: 2016.November.06. 23:42:03 »
I've read that it's possible for the atari st sound chip to do a pulse wave + modulation via timer interrupts. So the same should be possible with Dave. I suppose that someone has already tried it. However I've experimented a little and got stuck...

It's quite easy to get a pulse wave with the sound interrupts. I'm using one channel and change the frequency at each interrupt to change the square wave into a pulse wave. One time the interrupt sets the channel amplitude to zero the other time it sets it to 63. The interrupt frequency codes A, B are such that A+B=2*base_sound_frequency_code. For A=B=bsfc we get the normal square wave.

When I introduce the modulation I have a few problems:
* the sound is not audible at every run of the program (via dave emulation I saw that I need to be setting the amplitude to zero when chn.state1==1 (dave.cpp of ep128emu), but I don't know if that's the case
* I can't play other channels - one of the sounds will not be audible or so it seems
* I can't use video interrupts for the modulation changes because the sound gets corrupted
(I want the modulation to run at 50Hz/16 for example)

Maybe someone can help to solve the problems or just say that it's no use with Dave capabilities...



 

Offline ergoGnomik

  • EP lover
  • *
  • Posts: 764
  • Country: hu
  • Stray cat from Commodore alley
  • OS:
  • Windows 7/Server 2008 R2 Windows 7/Server 2008 R2
  • Browser:
  • Opera 9.80 Opera 9.80
    • View Profile
Re: Pulse Width Modulation on Dave
« Reply #1 on: 2016.November.07. 06:26:22 »
This is only my theory, and I'm not a competent EP programmer at all.

Best would be using the same channel locking technique that, I think, IstvanV came up with for playing 4ch digis. It uses some filtering method to trick two channels into producing DC levels. You should apply it to channel 1, and use channel 0 to provide timer interrupt. Don't mix timer and video interrupts, they will pretty much always be asynchronous. Modulate the sound in the main program, but only signal the change to the interrupt, don't make it. Apply the effect of modulation in the B phase of your timer interrupt.

However, I don't think there is too much worth in doing PWM beyond the technical achievement. PCM is much easier to use.

Offline ssr86

  • EP user
  • *
  • Posts: 359
  • Country: pl
  • OS:
  • Windows 7/Server 2008 R2 Windows 7/Server 2008 R2
  • Browser:
  • Firefox 49.0 Firefox 49.0
    • View Profile
Re: Pulse Width Modulation on Dave
« Reply #2 on: 2016.November.07. 06:56:59 »
I think I've found Istvan's code that you mentioned - it's in the source for sndplay in initDAC procedure. But I will need some more time to actualy understand what's going on there ;P. Something with forcing the noise channel to always output on state etc... Looked only briefly...
I've tried to do everything on single channel to not sacrifice any of the other channels...

I've looked up some more about how atari st musicians do their "sid" instruments which I think they call "timer instruments" and there is another approach based on short-samples with interpolation... I've found that a couple of guys work/worked on similar techniques for the cpc and I've tried BCS's tracker (from cpcwiki forum) AYAY kaeppttn (https://github.com/BetaSoftCologne/AYAY) and it sounds quite good. But I don't know how they manage the pulse modulation - probably switching between different short samples...

I don't know the difference between pwm and pcm :oops: . I need to look it up...

Offline ssr86

  • EP user
  • *
  • Posts: 359
  • Country: pl
  • OS:
  • Windows 7/Server 2008 R2 Windows 7/Server 2008 R2
  • Browser:
  • Firefox 49.0 Firefox 49.0
    • View Profile
Re: Pulse Width Modulation on Dave
« Reply #3 on: 2016.November.07. 07:08:35 »
Did you by PCM mean playing sample based music like mods or playing wav files?
I'm looking more for something like the atari sceners do with their ay-3-8192 clone + the additional possibilities that the timer interrupts give. So short 8-16byte samples and maybe some bigger for digidrums but I don't really know how much those need.

BTW playing with samples it looks that a distorted guitar 1-bit sample sounds quite good and I don't hear a big difference between the same sample played as 6-bit and 1-bit... But that's only the case with distortion ;P (I assume that this is rather obvious but I haven't ever played around with sample playing or sound synthesis)

Offline ergoGnomik

  • EP lover
  • *
  • Posts: 764
  • Country: hu
  • Stray cat from Commodore alley
  • OS:
  • Windows 7/Server 2008 R2 Windows 7/Server 2008 R2
  • Browser:
  • Opera 9.80 Opera 9.80
    • View Profile
Re: Pulse Width Modulation on Dave
« Reply #4 on: 2016.November.07. 08:34:13 »
Yes, the normal amplitude changing way of playing digital sound is called PCM. Actually, but this is only my way of simplifying the thing, in PWM you approximate the voltage levels produced by PCM with rapid voltage spikes that average out in time to said levels. Yours is actually the naïve method which is prone to producing glitches. The more practical method is having constant sample playback rate and spreading the 0 and 1 bits as evenly as possible. That way changing the emulated "sample" won't cause strong glitches (it could be almost considered as being automagically interpolated).

I forgot to mention in my previous post that you should run a counter in your irq handler's A phase to provide synchronization to the main program.

Offline IstvanV

  • EP addict
  • *
  • Posts: 4806
  • OS:
  • Linux Linux
  • Browser:
  • Firefox 49.0 Firefox 49.0
    • View Profile
Re: Pulse Width Modulation on Dave
« Reply #5 on: 2016.November.07. 08:36:10 »
One possible way to implement PWM is using ring modulation (XNOR) between two channels running at the same frequency but different phase:
* pwm_effect_asm.ep128s (192.77 kB - downloaded 63 times.)
To delay channel 2 relative to channel 0 by a known amount of time, the sync bits of port A7h are used, they force the outputs of both channels to zero and reload the counters. Before doing this, channel 2 is set up to run at a higher frequency (which determines the pulse width), then once the counters are allowed to run again by writing 0 to port A7h, the channel 2 frequency is set to the same value as that of channel 0.

I think I've found Istvan's code that you mentioned - it's in the source for sndplay in initDAC procedure. But I will need some more time to actualy understand what's going on there ;P. Something with forcing the noise channel to always output on state etc... Looked only briefly...

It basically uses the output of channel 3 as the noise clock, that is possible by enabling ring modulation on channel 1, and then channel 1 (which is forced to 0 state with the sync bit) is set to be the clock source. The ring modulation is periodically toggled on and off a number of times, and finally the clock source is set to channel 2 that always outputs 0 because of the sync bit. Channel 1 can then be used for other purposes. The trick is to create a stable state only when the noise output is 1:
- if channel 3 outputs 0, then the result of the ring modulation with channel 1 (= 0) is 0 XNOR 0 = 1
- if channel 3 outputs 1, then it is 1 XNOR 0 = 0
- when the ring modulation is disabled or the input is channel 2, the noise clock is 0
So, when the noise channel outputs 0, its input becomes a square wave, otherwise it is a stable 0 to keep the 1 output level that has already been found. Since the noise generators are implemented using LFSRs, they are guaranteed not to output runs of 0's or 1's longer than the size of the shift register, and more than that number of ring modulation on/off cycles will always find a 1 in the sequence.
« Last Edit: 2016.November.07. 08:39:55 by IstvanV »

Offline ssr86

  • EP user
  • *
  • Posts: 359
  • Country: pl
  • OS:
  • Windows 7/Server 2008 R2 Windows 7/Server 2008 R2
  • Browser:
  • Firefox 49.0 Firefox 49.0
    • View Profile
Re: Pulse Width Modulation on Dave
« Reply #6 on: 2016.November.07. 12:19:36 »
Don't mix timer and video interrupts, they will pretty much always be asynchronous.
One more thing about the problem with having sound and video interrupts both at the same time.
Just enabling the INT1 interrupts corrupted the sound very noticeably. I've thought that I'd be at least able to use the other interrupt for changing a flag...but even that doesn't seem to be possible. Without this any synchronization with the video become somewhat complicated if the sound interrupt frequencies will be variable.

Offline Zozosoft

  • EP addict
  • *
  • Posts: 13336
  • Country: hu
  • OS:
  • Windows XP Windows XP
  • Browser:
  • Firefox 49.0 Firefox 49.0
    • View Profile
    • http://enterprise.iko.hu/
Re: Pulse Width Modulation on Dave
« Reply #7 on: 2016.November.07. 12:25:49 »
One more thing about the problem with having sound and video interrupts both at the same time.
You can read the interrupt source from port B4h. Just needed when reset the actual interrupt latch (write port B4h), still enable the other interrupt source (and don't reset the other interrupt latch).

Offline ssr86

  • EP user
  • *
  • Posts: 359
  • Country: pl
  • OS:
  • Windows 7/Server 2008 R2 Windows 7/Server 2008 R2
  • Browser:
  • Firefox 49.0 Firefox 49.0
    • View Profile
Re: Pulse Width Modulation on Dave
« Reply #8 on: 2016.November.07. 12:52:51 »
You can read the interrupt source from port B4h. Just needed when reset the actual interrupt latch (write port B4h), still enable the other interrupt source (and don't reset the other interrupt latch).
I think I've done it that way (don't look at the asm file I attached in my original post becuase that was when I've tried different values)

Code: [Select]
        in a,($b4); for checking the kind of interrupt we are in
        bit 4,a   ; INT1 ? (video interrupt)
        jp nz,video_interrupt

[...]

vint_end:
        ld a,31h        ; reset INT1 interrupt latch
        or c            ;
        out (0b4h),a    ;

        ei
        ret


sint_end:
        ld a,13h        ; reset INT1 interrupt latch
        or c            ;
        out (0b4h),a    ;

        ei
        ret

I'll try later, maybe did something wrong.

Offline Zozosoft

  • EP addict
  • *
  • Posts: 13336
  • Country: hu
  • OS:
  • Windows XP Windows XP
  • Browser:
  • Firefox 49.0 Firefox 49.0
    • View Profile
    • http://enterprise.iko.hu/
Re: Pulse Width Modulation on Dave
« Reply #9 on: 2016.November.07. 12:57:19 »
Values looking good, but what is in the C?

Offline ssr86

  • EP user
  • *
  • Posts: 359
  • Country: pl
  • OS:
  • Windows 7/Server 2008 R2 Windows 7/Server 2008 R2
  • Browser:
  • Firefox 49.0 Firefox 49.0
    • View Profile
Re: Pulse Width Modulation on Dave
« Reply #10 on: 2016.November.07. 13:38:05 »
c held copy of the value read from $b4. Maybe I messed up something when commenting/deleting/changing lines of code. Need to try again if you say that it should be feasible.

Offline ssr86

  • EP user
  • *
  • Posts: 359
  • Country: pl
  • OS:
  • Windows NT 6.2 Windows NT 6.2
  • Browser:
  • Firefox 49.0 Firefox 49.0
    • View Profile
Re: Pulse Width Modulation on Dave
« Reply #11 on: 2016.November.08. 18:39:44 »
I've managed to mend the code to use both sound and video interrupts. The problem with not being able to play another channel also dissapeared. There were a two errors:
* I've tested bit 4 (enable INT1) instead of bit 5 (INT1 latch set) to choose which interupt to jump to ...a stupid error... :oops:
* but what's somewhat strange for me - it appears that you can't use saved value of $b4 or do "in a,($64); or 3;out ($b4),a" at interrupt end - I needed to use concrete values - $13 for sound- and $31 for video interrupt

Offline IstvanV

  • EP addict
  • *
  • Posts: 4806
  • OS:
  • Linux Linux
  • Browser:
  • Firefox 49.0 Firefox 49.0
    • View Profile
Re: Pulse Width Modulation on Dave
« Reply #12 on: 2016.November.08. 18:54:20 »
When reading the port, the enable interrupt bits actually return the current state of the input, that is, in the case of bit 4, the VINT bit of the current LPB. Since INT1 and INT2 are triggered by the falling edge of the input, bit 4 will usually be zero after a video interrupt.

Offline ssr86

  • EP user
  • *
  • Posts: 359
  • Country: pl
  • OS:
  • Windows NT 6.2 Windows NT 6.2
  • Browser:
  • Firefox 49.0 Firefox 49.0
    • View Profile
Re: Pulse Width Modulation on Dave
« Reply #13 on: 2016.November.08. 19:01:49 »
Makes sense now :oops:

Offline ssr86

  • EP user
  • *
  • Posts: 359
  • Country: pl
  • OS:
  • Windows 7/Server 2008 R2 Windows 7/Server 2008 R2
  • Browser:
  • Firefox 50.0 Firefox 50.0
    • View Profile
Re: Pulse Width Modulation on Dave
« Reply #14 on: 2016.December.14. 15:31:32 »
One possible way to implement PWM is using ring modulation (XNOR) between two channels running at the same frequency but different phase:
(Attachment Link)
To delay channel 2 relative to channel 0 by a known amount of time, the sync bits of port A7h are used, they force the outputs of both channels to zero and reload the counters. Before doing this, channel 2 is set up to run at a higher frequency (which determines the pulse width), then once the counters are allowed to run again by writing 0 to port A7h, the channel 2 frequency is set to the same value as that of channel 0.
I've came back to this thread to reread something and became a little embarassed that I somehow haven't read this earlier... I've got to do PWM via ring modulation with setting channel 2 frequency to channel 0's +- a small detune of the freqcode.... Although I've read the dave emulation code I somewhat have some problems getting a grasp of how to use the sync... :oops:
« Last Edit: 2016.December.14. 16:20:28 by ssr86 »