Jump to content
IGNORED

Asymmetric Squarewaves


analmux

Recommended Posts

I've been experimenting with timer irqs, and this is the result:

 

When we use channel 2 for both timer irq and sound at once, and we use the interrupt to write alternating pitches to audf of channel two, we can make asymmetric squarewaves, like the picture titled wave below, the picture is a recorded pokey sound. Now we're able to make more NES-alike sounds, we have a variable pulsewidth now (like a c64).

 

The principle:

When pokey makes a sound it resets a counter and every 1/63921th of a second it's incremented untill the value 'f' stored in AUDF is reached, so it waits (f+1)*(1/63921) seconds when the Pokey-basefrequency is 63921 Hz. After counting, the wave goes from up to down, or from down to up. This means that we have a frequency:

 

Pitch = 63921/(2*(f+1))

because in one period of the waveform a squarewave has an up and a down side. Pokey generates 2 irq's per period, one at the transition from up to down, and one at the transition from down to up.

 

When we define f1 and f2 in such a way that f1+f2 = 2*f and we do this:

(*) At the first (even) IRQ we write f1 to AUDF

(*) At the second (odd) IRQ we write f2 to AUDF

we can change the timbre to an asymmetric waveform with an excentricity epsilon. I've written down how to compute f1 and f2, with given f and epsilon, in the picture labeled equation

Link to comment
Share on other sites

I also wrote a demo (to be runned on real machine). Sourcecode included

 

Just bootup main.atr and plug in joystick in port 0.

 

Push trigger to start a sound. The program starts at f = 72, f1=f2=f.

 

With left/right you can change the excentricity

With up/down you can change the pitch.

 

Watch the grey bands on screen to see how the pulses evolve.

Link to comment
Share on other sites

This is the sourcecode:

 

; Pokey demo 1 for atari xl/xe series
; 'variable pulsewidth'
; january 31  2004
; by Analmux
; written for xasm





trig0	equ	$d010

colbk	equ	$d01a

audf0	equ	$d200

audc0	equ	$d201

audf1	equ	$d202

audc1	equ	$d203

audf2	equ	$d204

audc2	equ	$d205

audf3	equ	$d206

audc3	equ	$d207

audctl	equ	$d208

stimer	equ	$d209

irqen	equ	$d20e

skctl	equ	$d20f

porta	equ	$d300

portb	equ	$d301

nmien	equ	$d40e

nmist	equ	$d40f



z_f  equ	$80

z_f1  equ	$81

z_f2  equ	$82

z_endflag	equ	$83

z_flag1  equ	$84

z_flag2  equ	$85

z_phx  equ	$86

z_joy  equ	$87



stack  equ	$0100

dliv  equ	$0200

vbiv  equ	$0222









org	$2000





start

jsr	init

st_0	lda	trig0

bne	st_0

jsr	start_sound

st_l	lda	z_endflag

beq	st_l

jmp	st_0







init

lda	#0

sta	nmien

ldx	#8

ip_0	sta	audf0,x

dex

bpl	ip_0

lda	#72

sta	z_f

sta	z_f1

sta	z_f2

mva	#3  skctl

sei

mva	#$fe  portb

mwa	#nmi_handler	$fffa

mwa	#irq_handler	$fffe

mwa	#vbi  vbiv

cli

rts







start_sound

mva	#0  irqen

sta	z_endflag

sta	z_flag1

sta	z_flag2

mva	#2  irqen	;enable audf1 timer irq

sta	stimer  	;start timer

mva	z_f  audf1

mva	#$a8  audc1

cli

mva	#64  nmien

rts







irq_handler

pha

lda	irqen

and	#2

beq	ih_0

pla:rti

ih_0

mva	#253  irqen

mva	#2  irqen

lda	z_flag2

eor	#1

sta	z_flag2

tax

lda	z_f1,x

sta	audf1

lda	z_flag1

eor	#8

sta	z_flag1

sta	colbk

lda	trig0

beq	ih_1

inc	z_endflag

stx	z_phx

tsx

inx

inx

lda	stack,x

ora	#4

sta	stack,x

ldx	z_phx

mva	#0  audc1

sta	colbk

sta	nmien

ih_1	pla

rti







nmi_handler

bit	nmist

bpl	vbi

vbi	cld

pha

txa:pha

tya:pha

mva	porta  z_joy

lsr	z_joy

bcs	vb_0

jmp	joy_up

vb_0	lsr	z_joy

bcs	vb_1

jmp	joy_down

vb_1	lsr	z_joy

bcs	vb_2

jmp	joy_left

vb_2	lsr	z_joy

bcs	evbi

jmp	joy_right

evbi	pla:tay

pla:tax

pla:rti





joy_up

lda	z_f

cmp	#10

beq	ju_x

dec	z_f

lda	z_f

sta	z_f1

sta	z_f2

ju_x	jmp	evbi





joy_down

lda	z_f

cmp	#255

beq	jd_x

inc	z_f

lda	z_f

sta	z_f1

sta	z_f2

jd_x	jmp	evbi





joy_left

lda	z_f1

cmp	#10

beq	jl_x

lda	z_f2

cmp	#255

beq	jl_x

dec	z_f1

inc	z_f2

jl_x	jmp	evbi





joy_right

lda	z_f1

cmp	#255

beq	jr_x

lda	z_f2

cmp	#10

beq	jr_x

inc	z_f1

dec	z_f2

jr_x	jmp	evbi







org	$2e0

dta	a(start)

Link to comment
Share on other sites

raster must be interested in this kind of stuff... i don't understand 1% of that! very cool... i'll have to check it on real machine tonight... (TMR i hadn't the chance to play around with CC for the review i promissed.... but will do today)

 

sometimes i wish god had gave me a more math & physic experience but i am a pure marketing guy with some programming experience... :D

 

ps. wavelab is one of the ugliest software around but very powerful... hahahha...

Link to comment
Share on other sites

Sound good! :)

 

Like i though you`ve used 2 channel to do this - but the result is cool!

 

Hve: there were rumours of discountinuing the RMT project, due to `coming soon` new version of Jaskier`s TMC :mad: - i wish that they were only rumours...

Link to comment
Share on other sites

raster must be interested in this kind of stuff... i don't understand 1% of that!

I'm understanding 100% :D

The only thing I'm thinkink is:

it is possible to play 2 differents sounds on one channel? If yes, there is the possibility to play stereo music on one pokey :) 8)

 

Unfortunatelly pokey generates irq only for 3 channels :(

 

P.S. TMC 2.0 will be of course Atari executable.

Link to comment
Share on other sites

but will jaskier make a PC TMC 2.0 or will it be again a atari8bit version only? i would prefer PC tool... just because more comfortable...

 

I don`t think if Jaskier will make PC version of it - it`s rather dedicated to people using the REAL stuff. So Raster can continue his project without any worrings, i think.

Link to comment
Share on other sites

Off Topic:

 

If you want to avoid the numbering of the formulae in LaTeX, simply append an asterisk to the eqnarray.

 

You write:

 

begin{eqnarray*}

Your equations

end{eqnarray*}

 

Yes thanks, but the numbering didn't bother me.

 

-----

 

Well, for those who do not understand the principle completely (Heaven):

 

The excentricity 'e' is always a value between 0 and 1.

when e=0 we have f1=f2=f and the wave will be perfectly symmetric.

 

f1 is the pulsewidth of the upper part of the wave

f2 is the pulsewidth of the lower part of the wave

 

so when f1=f2 we have the original squarewave.

 

when e=0.99999 we have f1=0.99999*f and f2=0.00001*f and we have a very small peak instead. when e=1 we don't have a wave at all.

 

Now we can solve some tuning problems too.

 

When we want a note between f=34 and f=35 (that is: 34.5) we define f1=34 and f2=35 then the effective pulsewidth is f=(f1+f2)/2=34.5 and the excentricity is minimal, so we have a true pitch of 34.5 and an almost symmetric squarewave.

 

To answer another question:

it is possible to play 2 differents sounds on one channel? If yes, there is the possibility to play stereo music on one pokey

 

hmmm, could be, but you must expect more distortion, as it's not possible to play clear waves (without a lot more cpu investment)

 

Maybe when we have a four-step alternating pitch instead of two-step, then maybe we can (even two assymetric waves). I must experiment with it at once.

Link to comment
Share on other sites

To answer another question:
it is possible to play 2 differents sounds on one channel? If yes, there is the possibility to play stereo music on one pokey

 

hmmm, could be, but you must expect more distortion, as it's not possible to play clear waves (without a lot more cpu investment)

 

Maybe when we have a four-step alternating pitch instead of two-step, then maybe we can (even two assymetric waves). I must experiment with it at once.

 

It shurely will not be possible to play stereo via one pokey because all channels are hard-wired in the chip itself.

 

...

 

How much CPU does this cost ?

Will it be possible anyway to combine those techniques with G2F ... I believe not.

Link to comment
Share on other sites

It shurely will not be possible to play stereo via one pokey because all channels are hard-wired in the chip itself.

 

OK I say it wrong. I mean to play 8 channel (2 pokeys) music on only one pokey.

 

How much CPU does this cost ?  

Will it be possible anyway to combine those techniques with G2F ... I believe not.

Surely not. You cannot combine IRQ and DLI in one time.

 

Anyway I must say that You probably can't use this technique on more than one channel. When there are 2 sources of IRQ the second must wait till finish of first IRQ procedure. It affects the sound for sure.

 

But on only one channel with DLI turned off (and better also all screen) ? Maybe yes. I must try it when I get my machine back (it is in stereo upgrade now).

Link to comment
Share on other sites

It shurely will not be possible to play stereo via one pokey because all channels are hard-wired in the chip itself.

 

...

 

How much CPU does this cost ?  

Will it be possible anyway to combine those techniques with G2F ... I believe not.

 

I fail to understand your arguments. Pokey has only a MONO audio output, so you'd really need 2 of them to have stereo.

 

This technique is hard to combine with G2F and especially GED, however MCS (with eventually a minimum of DLIs) is still possible.

 

Playing two sounds via one channel is very tricky, I've tried to write a 4 step pulse. You can download it in pokeydemo2 below. You don't hear two notes.

 

reason:

I've defined f1, f2, f3, f4 for the 4 pulsewidths of the four steps.

now h=f1+f2+f3+f4 is held constand (when changing excentricity of wave 1 and wave 2). So the resulting wave is h-periodical. But a two-note wave is Never h-periodical, but something else, I'll explain later.

 

Instructions for the demo:

when booting: if you hold down Start (while loading the prog, and not while the OS checks for a Tape-boot) before the loading ends the Audctl register is changed from 0 to 1 to change the pokey-basefrequency from 64 khz to 15 khz.

 

It sounds constantly:

joy up/down: change pitch (wave 1)

joy left/right: change excentricity (wave 1)

joy up/down + trigger: change pitch (wave 2)

joy left/right + trigger: change excentricity (wave 2)

 

Fun: when you choose 15khz basefreq. you can set the grey flickering bands still, and you can see clearly how the timing of the 4 step pulse alters when only changing excentricity of wave 1 and 2.

Link to comment
Share on other sites

It's best to use this technique only on one channel, but I don't think that multiple channel IRQ's are a problem as the changing of AUDF is not very timing-critical, as it's only checked by pokey at the end of a counting loop, the only thing that's important is THAT the audf is changed at an average timing.

 

You also won't have to switch off the screen. It's nothing like playing digital sound, you may call it PSEUDO-SAMPLING, as with the avarage pitch = 72 we only have 880 updatings per second = 17 updates per frame. No problem.

 

Now, this is the sourcecode for the second demo (4 step):

 

; Pokey demo 1.2 for atari xl/xe series
; polyphonic 'variable pulsewidth'
; 4 step alternating pulsewidth
; february 1  2004
; by Analmux
; written for xasm





trig0	equ	$d010

colbk	equ	$d01a

consol	equ	$d01f

audf0	equ	$d200

audc0	equ	$d201

audf1	equ	$d202

audc1	equ	$d203

audf2	equ	$d204

audc2	equ	$d205

audf3	equ	$d206

audc3	equ	$d207

audctl	equ	$d208

stimer	equ	$d209

irqen	equ	$d20e

skctl	equ	$d20f

porta	equ	$d300

portb	equ	$d301

nmien	equ	$d40e

nmist	equ	$d40f



z_f  equ	$80;base PW (Pulse Width) of first note

z_g  equ	$82;base PW of second note

z_f1  equ	$88;upper side PW of first	note

z_f2  equ	$89;lower side PW of first note	

z_g1  equ	$8a;upper side PW of second note

z_g2  equ	$8b;lower side PW of second note

z_endflag	equ	$90;note sustain

z_flag1  equ	$91;colbk grey/black toggle flag

z_flag2  equ	$92;(0-3) PW index

z_phx  equ	$93;temp x save register

z_joy  equ	$94;joystick shift register



stack  equ	$0100





org	$2000





start

jsr	init

jsr	start_sound

loop0	jmp	loop0





init

lda	#0

sta	nmien

ldx	#8  	;reset pokey sound

ip_0	sta	audf0,x

dex

bpl	ip_0

lda	consol

and	#1

eor	#1

sta	audctl

lda	#72

sta	z_f

sta	z_f1

sta	z_f2

sta	z_g

sta	z_g1

sta	z_g2

mva	#3  skctl	;enable sound

sei

mva	#$fe  portb	;changing interrupt vectors

mwa	#nmi_handler	$fffa

mwa	#irq_handler	$fffe

cli

rts







start_sound

mva	#0  irqen

sta	z_endflag

sta	z_flag1

sta	z_flag2

mva	#2  irqen	;enable audf1 timer irq

sta	stimer  	;start timer

mva	z_f  audf1	;set default pitch

mva	#$a8  audc1	;set generator a, volume 8

cli    ;enable irq

mva	#64  nmien	;enable vbi

rts







irq_handler

pha

lda	irqen

and	#2

beq	ih_0

pla:rti

ih_0

mva	#253  irqen	;clearing IRQ flags

mva	#2  irqen	;re-enabling timer IRQ

ldx	z_flag2

lda	z_f1,x

sta	audf1

inx

txa

and	#3

sta	z_flag2

lda	z_flag1

eor	#8

sta	z_flag1

sta	colbk

lda	#0

beq	ih_1



inc	z_endflag

stx	z_phx

tsx  ;finding stack offset of last pushed byte

inx

inx

lda	stack,x	;disable IRQs (sei) when returned from IRQ  :)

ora	#4	;bit 2 of pushed status reg = interrupt disable flag

sta	stack,x

ldx	z_phx

mva	#0  audc1

sta	colbk

sta	nmien



ih_1	pla

rti







nmi_handler

bit	nmist

bpl	vbi

rti

vbi	cld

pha

txa:pha

tya:pha



lda	trig0	;computing offset, dependent of trigger

eor	#1

asl	@

tax



mva	porta  z_joy

lsr	z_joy

bcs	vb_0

jmp	joy_up

vb_0	lsr	z_joy

bcs	vb_1

jmp	joy_down

vb_1	lsr	z_joy

bcs	vb_2

jmp	joy_left

vb_2	lsr	z_joy

bcs	evbi

jmp	joy_right

evbi	pla:tay

pla:tax

pla:rti





joy_up

lda	z_f,x

cmp	#10

beq	ju_x

dec	z_f,x

lda	z_f,x

sta	z_f1,x

sta	z_f2,x

ju_x	jmp	evbi





joy_down

lda	z_f,x

cmp	#255

beq	jd_x

inc	z_f,x

lda	z_f,x

sta	z_f1,x

sta	z_f2,x

jd_x	jmp	evbi





joy_left

lda	z_f1,x

cmp	#10

beq	jl_x

lda	z_f2,x

cmp	#255

beq	jl_x

dec	z_f1,x

inc	z_f2,x

jl_x	jmp	evbi





joy_right

lda	z_f1,x

cmp	#255

beq	jr_x

lda	z_f2,x

cmp	#10

beq	jr_x

inc	z_f1,x

dec	z_f2,x

jr_x	jmp	evbi







org	$2e0

dta	a(start)

Link to comment
Share on other sites

sounds like a racing game... ;)

 

you could even sell that "game" burnt onto cart... called "maniac bars"... in this exciting new game you task is to control the evil bars and controll them in the magnetic field not to move up and down anymore... hahahaha:) analmux...great work... and interesting to read....

Link to comment
Share on other sites

I've got both Atari800win2.6 and the newest version (3.3 or so). On both emus the demo doesn't work properly, so be sure to run it on a real machine.

Have you tried Atari800win PLus 4.0beta2 ?

As I said before I don't have real machine for now so I cannot say that it is working but definitely something is going on. Something expected I would say.

 

Atari800win PLus 4.0 has rewritten sound engine.

Link to comment
Share on other sites

Have you tried Atari800win PLus 4.0beta2 ?

As I said before I don't have real machine for now so I cannot say that it is working but definitely something is going on. Something expected I would say.

 

Atari800win PLus 4.0 has rewritten sound engine.

 

I've checked the version number. It is 4.0.beta2 that I have.

 

The effect in emulator is almost the same as on the real hardware, but the emulator skips every odd frame, and I can't adjust it.

Link to comment
Share on other sites

Sound good! :)

 

Like i though you`ve used 2 channel to do this - but the result is cool!

 

Hve: there were rumours of discountinuing the RMT project, due to `coming soon` new version of Jaskier`s TMC  :mad:  - i wish that they were only rumours...

 

You've got it wrong. It's only ONE channel.

 

The IRQ is generated by channel 2 (audf1), AND the sound is generated by channel 2 too. Not like sampling in which you use a 16bit channel to trigger IRQs at 22.050 kHz, and playing volume-only via another channel (though even the same channel could be used).

 

-----------

It would be cool to see this technique applied in RMT and TMC.

 

I don't know if I just re-invented the wheel now, but we can make a new standard sound-generating-technique out of this.

Link to comment
Share on other sites

The effect in emulator is almost the same as on the real hardware, but the emulator skips every odd frame, and I can't adjust it.

 

You mean that the display is refreshed at 25Hz? It affects sound?

 

Question to the stereo makers. It is possible to generate IRQ by the second pokey or only by the first?

Link to comment
Share on other sites

The effect in emulator is almost the same as on the real hardware, but the emulator skips every odd frame, and I can't adjust it.

 

You mean that the display is refreshed at 25Hz? It affects sound?

 

Question to the stereo makers. It is possible to generate IRQ by the second pokey or only by the first?

 

Display seems to be refreshed at 50 hz, but the program seems to freeze every odd frame, that is: screen is just normal, without grey bands, and no sound.

 

------------

 

If the IRQ line of the 2nd pokey is connected, then it can generate IRQ too, otherwise you'd need to solder an extra wire inside the computer: not a very difficult job.

 

@ Jaskier:

 

By the way, how many DLIs does TMC use?? On what places are they, and is the used DLI code long or short?

 

Maybe there is a way to combine DLI with IRQ simply by disabling interrupts ("SEI"), when DLI is runned, then after the DLI turn them on again ("CLI"). The IRQ flags will stay set until cleared, and a little retardation is not a real problem.

Link to comment
Share on other sites

Display seems to be refreshed at 50 hz, but the program seems to freeze every odd frame, that is: screen is just normal, without grey bands, and no sound.

 

Not on my emulator :)

 

If the IRQ line of the 2nd pokey is connected, then it can generate IRQ too, otherwise you'd need to solder an extra wire inside the computer: not a very difficult job.

 

I've asked my stereo maker. He is doing stereo without irq connected. He will have to make some changes :)

 

By the way, how many DLIs does TMC use?? On what places are they, and is the used DLI code long or short?

 

Maybe there is a way to combine DLI with IRQ simply by disabling interrupts ("SEI"), when DLI is runned, then after the DLI turn them on again ("CLI"). The IRQ flags will stay set until cleared, and a little retardation is not a real problem.

 

TMC 1.11 use about 10 DLIs to make screen so beautiful :)

TMC 2.0 has DLI every text line due to special text mode (8x6 points , 39 lines of text.)

 

On some dli-s the player is run so it takes up to 5000 cycles (during that some other dlis are run).

 

I can enable irq during dli to allow sound change, but the real problem is the dli start. I've observed several times that irq is able to BLOCK dli and the particular dli is NOT EVEN RUN!!! So I'm sure that I cannot mix DLI and IRQ. The workaround for that is to disable IRQ and observe the IRQST ($D20E) in loop. When the irq should happen (but is not due to SEI) the bit in IRQST is cleared and then you can start your own irq routine :) (Yes, disabling irq in CPU doesn't disables irq in all atari so you can check when the irq should happen and start the apropriate routine, funny isn't it?)

 

I've used this techinque several times for example in TMC when I read the pressed key. But when the music is playing I cannot check the IRQST register. The player routine is so long and I can miss several irq.

 

P.S. I have to freeze developing TMC 2.0 for a few days. The polish translation of new Harry Potter has been just released :) Sorry :)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...