Building a new AY player.

This forum is about audio tools, including samplers, sound trackers, sound chip editors, how to do sound effects, etc...
JamesD
Flight Lieutenant
Posts: 352
Joined: Tue Nov 07, 2006 7:38 am

Post by JamesD » Thu May 28, 2009 3:26 pm

The only thing I have left to do on this is exit gracefully. It returns to BASIC and then BASIC locks up. I'm guessing it's how the VIA is set but I haven't been able to save the current settings. Anyone know how this is set? If not I'll have to take a look at the ROM disassembly.

User avatar
Symoon
Archivist
Posts: 1169
Joined: Sat Jan 14, 2006 12:44 am
Location: Paris, France
Contact:

Post by Symoon » Thu May 28, 2009 5:29 pm

Short reply, not sure it's what you're looking for, but here's what the v1.1 ROM does to restore the VIA once a program has been saved (at #E93D)
JSR #E5F5 (erase line 0)
JSR #F9AA initialize VIA
JMP #EDE0 aloow IRQs on T1

User avatar
Twilighte
Game master
Posts: 819
Joined: Sat Jan 07, 2006 12:07 am
Location: Luton, UK
Contact:

Post by Twilighte » Thu May 28, 2009 5:35 pm

JamesD wrote:I'll need to know what is safe to use on page 0
Under BASIC..
00-0B is free
BB-BC is free
F3-F8 is free

If no BASIC then all 256 bytes of zero page may be used.

This one is from first message in thread.. all those many weeks back..
JamesD wrote:One thing that has been a problem on all these players is portability of music files. Many depend on inclusion of z80 or 68000 code in the file itself. While this may work well on a PC it's not exactly practical on all legacy hardware.
I can only imagine you are referring to SID files which are basically the music + code ripped out of C64 games and stuck in a file.

I find it difficult to understand the usefulness of this idea, though i do agree we have a real problem on portability of music files on legacy machines.
I am also slightly miffed why it is neccesary to modify the existing interrupt config, since the existing irq setup should be fine for most apps.

speed can easily be changed from 100hz to 50hz, and to process some other code during the irq is a simple 3 byte patch to page2.

Also, Do you really require 100% cpu to process the sound?
Sorry, i'm confused James.. or perhaps its my age!

JamesD
Flight Lieutenant
Posts: 352
Joined: Tue Nov 07, 2006 7:38 am

Post by JamesD » Fri May 29, 2009 9:04 am

Twilighte wrote: I can only imagine you are referring to SID files which are basically the music + code ripped out of C64 games and stuck in a file.
There are several formats that include the original binary code.
One of which is for the AY sound chip and includes Z80 code. There are trackers that generate portable data if you have a player.
I find it difficult to understand the usefulness of this idea, though i do agree we have a real problem on portability of music files on legacy machines.
The original idea (posted a couple years ago) was that it would give greater control over the music from within the player and still remain portable.

For example, you could also have the main game code interact with the player in a way that would allow smooth transitions from a section of a song to another. You could set a value in one of the song player memory locations that tells it to transition from one repeating section to another without abrupt change in the music.
So, you could implement a while loop in the song data itself that kept repeating a section until a flag told it to continue or to jump to a different section. The flag the main program modifies could even tell the player what section to transition to. And the transitions could be seamless.

You'll also notice my comment that I thought it would be to slow after I looked it over again and I dropped the idea.
I thought the interrupt would take too long but maybe that was just me not wanting to start over. I think the goal is good but it could be simpler to implement.
I am also slightly miffed why it is neccesary to modify the existing interrupt config, since the existing irq setup should be fine for most apps.

speed can easily be changed from 100hz to 50hz, and to process some other code during the irq is a simple 3 byte patch to page2.
:shock: Wow, "miffed". My first Oric program *ever* and you are "miffed". You seem to be taking it rather personal.

Some songs are written on NTSC machines and they play too slow on a PAL machine. If you have a timer you just alter the timer and don't have to do any math in the player to correct the wait time problem. And guess what the only timer example I found in the forum does? Exactly what I did because I was following the example... unless I screwed up which is entirely possible but I believe someone replied in that thread they had the same problem when they used the example.
Also, Do you really require 100% cpu to process the sound?
Sorry, i'm confused James.. or perhaps its my age!
:twisted: Moohahahaha... all your cpu belong to us!

But seriously, I understand your confusion and it's that way for a very selfish reason. First of all, the code I posted had nothing to do with the original concept other than it's a music player of sorts, though a rather limited one. It was a direct port of a Z80 program, which btw, did exactly the same thing (100% cpu). The original Z80 code didn't even use an interrupt at all, it polled the hardware looking for the TOF signal.

I'm working on an AY sound chip upgrade for the Radio Shack MC-10. I was already going to port the Z80 code to the 6803 as a demo/test for the hardware and I figured, what the hell, let's see what it looks like on other CPUs... so I ported it to the 6809 (CoCo Speech & Sound Pak) and the 6502 (Oric). It was a cpu vs cpu comparison I was interested in. And yes, the 6803 and 6809 code uses 100% of the CPU cycles even though it doesn't need to. It was do that or fix the Aquarius Z80 code to make it work right.

However, I'm not sure it's worth the effort to fix other than to demonstrate the proper way to do it. The player is very limited and I don't even know what tracker the data came from so I don't even know how to create a different song for it. If someone figures that out, let me know. I have a hunch the data was ripped from a game.

I'd be happy to fix it if people are actually interested... but I kinda figured once I had time I'd pick a popular tracker and use what I learned to make a player for that tracker format.

JamesD
Flight Lieutenant
Posts: 352
Joined: Tue Nov 07, 2006 7:38 am

Post by JamesD » Fri May 29, 2009 9:09 am

Symoon wrote:Short reply, not sure it's what you're looking for, but here's what the v1.1 ROM does to restore the VIA once a program has been saved (at #E93D)
JSR #E5F5 (erase line 0)
JSR #F9AA initialize VIA
JMP #EDE0 aloow IRQs on T1
Hmmmm... guess I could just make those calls if it works but it sounds like there might be a better way from what Twilighte wrote.
At last I know where to look.

User avatar
Twilighte
Game master
Posts: 819
Joined: Sat Jan 07, 2006 12:07 am
Location: Luton, UK
Contact:

Post by Twilighte » Fri May 29, 2009 9:16 pm

Ok, seems i have a bit more time tonight. lets see now..

Oric IRQ's can be generated from various sources but all jump to the vector specified in $FFFE. This is within the same memory space as the Oric ROM and in v1.1 (not sure about V1.0) is set to $0244 which is normal RAM(Page 2).
Under BASIC this contains a direct jump back into the Oric ROM to $EE22 which contains the complete irq handler. At the end it jumps back down to $024A which usually holds an RTI (Return from Interrupt).
Oric only uses Timer1 to generate an interrupt at 100Hz but this may be modified by setting Timer1 16 bit latch registers in $306/$307.

Technically you can set the latch registers to anything but obviously it will affect the timing of fundamental parts of Oric BASIC such as the WAIT statement period, the cursor blink rate and the speed at which the keyboard is scanned.

Now you want to redirect the irq routine to process your own program. Well the kind people at Oric gave us 2 extra bytes after the RTI in $24A which allows us to DOKE your routine address into 24B and write a 4C into 24A. Now remember (i am sure you are aware) on entering your irq routine you must preserve all 3 registers and end with an RTI.

Even though the Orics IRQ handler is a piece of dung (effieicency wise) compared to modern techniques it was perfectly able to run a Sonix tune alongside BASIC at the default 100hz and i can tell you, i am not so proud of some elements of Sonix code nowadays.
JamesD wrote:One of which is for the AY sound chip and includes Z80 code.
Sorry, i am not aware of this one at all.. please let me know, i would be interested if nothing else.

JamesD
Flight Lieutenant
Posts: 352
Joined: Tue Nov 07, 2006 7:38 am

Post by JamesD » Fri May 29, 2009 10:49 pm

Ok, I had a few minutes to work on this.
I saved the original VIA Timer 1 latch content and installed my interrupt handler with a JMP _VBLIrq (my interrupt handler) in place of the RTI on memory page 2.
On exit I store an RTI back in place of the JMP and restore the timer to it's original state.
Now BASIC seems to work fine on exit.

Changing the code to not use 100% CPU time won't be difficult but I don't have time today. I'll post the current changes back to the source.

I gotta say, Oriculator has made this much easier than Euphoric under DOSBox.

JamesD
Flight Lieutenant
Posts: 352
Joined: Tue Nov 07, 2006 7:38 am

Post by JamesD » Fri May 29, 2009 11:10 pm

Twilighte wrote: Sorry, i am not aware of this one at all.. please let me know, i would be interested if nothing else.
I *think* it was somewhere on this site but I'm not sure.
http://bulba.untergrund.net/main_e.htm

JamesD
Flight Lieutenant
Posts: 352
Joined: Tue Nov 07, 2006 7:38 am

Post by JamesD » Fri May 29, 2009 11:36 pm

Twilighte wrote:Now remember (i am sure you are aware) on entering your irq routine you must preserve all 3 registers and end with an RTI.
Correction, I only have to preserve A, X, or Y if I modify them.
BIT doesn't alter A, just the condition codes.
INC doesn't alter A, X, or Y either.
That means no cycles for push/pull.

I could put the counter on page zero to save clock cycles in the INC.
<edit>
I guess maybe you were referring to when I move the playline code into the interrupt handler.

User avatar
Dbug
Site Admin
Posts: 2389
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Post by Dbug » Sat May 30, 2009 11:36 am

I think he meant that as a general statement: "The registers have to be in the state they were when your code was called" :)

Now, storing/restoring, or not modifying, same thing :)

JamesD
Flight Lieutenant
Posts: 352
Joined: Tue Nov 07, 2006 7:38 am

Post by JamesD » Sat May 30, 2009 3:49 pm

He said preserve and I took it as save.

User avatar
Twilighte
Game master
Posts: 819
Joined: Sat Jan 07, 2006 12:07 am
Location: Luton, UK
Contact:

Post by Twilighte » Sat May 30, 2009 5:43 pm

I meant it as a general rule as Dbug stated. But doesn't matter.

Anyway, what i don't see is your idea of creating a virtual processor in the oric for controlling sound. Sure, it is useful for sound effects but music?
From the light reading of your documentation it appears you do not base anything on notes but rather on actual register values. If this is so (and knowing me i've got completely the wrong end of the stick) then expecting the same music data to work on a c64 SID as on an AY is just not the same since a SID pitch range is 16 bit and AY is 12 bit so sounds won't behave the same.
That's why the sound effect handler in AudioTracker (using a similar script type language to control pitch, note, volume and timbre) gives control over notes more often than over pitch. Or rather pitch can be relative to the note. Controlling a note is much more universal than controlling an undefined resolution of pitch.

To me, a script is much better to control sound. The script language of Audiotracker permits the use of variables, counters and conditional branches to facilitate the control of a musical note or sound effect.
Furthermore it allows to work either in absolute or relative modes. Relative modes always work relative to the base note (taken from the pattern data) so are much more useful for the controlling of the music note whereas absolute mode permits a much wider range of progressive effects through the accumulation of math operations in the script.
:P

JamesD
Flight Lieutenant
Posts: 352
Joined: Tue Nov 07, 2006 7:38 am

Post by JamesD » Sun May 31, 2009 5:29 pm

I've repeatedly said I wasn't going to pursue the virtual processor idea. As I said before... the current player is a port of something someone did on the Z80 and isn't my idea at all. It even says so in the header to the code.

To be honest, portable music formats that play on any sound chip are nice for music but if you are counting every last clock cycle they are processor intensive and support for all tracker features can make a player pretty big. They also don't play on every sound chip anyway because different sound chips have a different number of channels or envelope generation and emulating such features is cpu intensive. If you have music during game play you also have to be careful and reserve a channel(s) for sound effects which makes it even more difficult.

Just dumping values to registers is fast and produce anything the music player can but the source data can be huge. On the other hand the player is simple and small. If speed was a #1 concern I'd even look at unrolling the register setting loop so it could handle multiple registers before actually looping.

Keeping the music data a reasonable size but without getting really CPU intensive is definitely a challenge. With a few additional features like repeats and such, you can shrink the music data based on registers quite a bit but at the cost of adding additional logic.

I might try just writing a converter that generates a file with the register values from a portable format. That way it can be done on a PC where CPU time doesn't matter. But if I pick a big song to test it on it's gonna get ugly.

Just an FYI, I figured I'd use a converter to generate the virtual processor data from a tracker.

User avatar
Twilighte
Game master
Posts: 819
Joined: Sat Jan 07, 2006 12:07 am
Location: Luton, UK
Contact:

Post by Twilighte » Mon Jun 01, 2009 9:31 pm

I agree with everything you said in your last post and apologies for getting the wrong end of the stick.

I agree that scripts do potentially use alot more cpu even though the actual memory footprint is very small.

Mused was my first music editor program (written completely in basic i think) and was actually a good editor. It was a sequencer in that it was simple 3 lists in memory holding musical notes and volumes for each of the 3 chip channels. cpu wise it was fast. it was also not bad on memory usage though it played slowly (basic) and it lacked effects on notes.

Sonix i think was a good tracker because it was very simple. it didn't consume alot of cpu and once i'd managed to create a compiler the footprint was fairly small (i think the biggest song(25 minutes) was about 10K) including player and the smallest about 4K.

AYT, AT and various others used the script idea for effects. The memory footprint was comparable but the cpu usage was definately higher.

It is a constant fight between speed, memory, features and playability for me.

But i definately think there is a better way than i have done so far. It just angers me that when i build up the hype of a new Oric tracker(like AT and AYT) i try to put as much in it as possible instantly forgetting the thing just won't run alongside basic or will be totally ununderstandable to everyone apart from me.

JamesD
Flight Lieutenant
Posts: 352
Joined: Tue Nov 07, 2006 7:38 am

Post by JamesD » Tue Jun 02, 2009 1:11 am

FWIW, I think a virtual processor is a stretch for what I really intended originally.
More like embedded commands and reserved storage locations.

<edit> (This is a modification of just dumping values to registers)
Instead of just checking to see if # of registers to load is zero it would check for less than or equal to zero. Then it would take the value as a command number and jump to the appropriate routine from a table of pointers.
Here is how the jump would be done (ok, so I did spend a few minutes on it):

Code: Select all

commands
	sty	tempy

	; adjust the command pointer to get command table offset
	and	#%01111111	; mask off top bit
	rol			; bit shift = multiply by 2 (addresses are 2 bytes in size)

	; get command address from command pointer table (self modifying code)
	tay
	lda	(commandtable),y
	sta	ijmp+1
	lda	(commandtable),y
	sta	ijmp+2
ijmp	jmp	commandtable	; self modifying code, playsong end replaced with current command address
That allows for over 50 commands but only a handful would really be needed to do loops and a few special effects.
Add, subtract, conditional branches, output to register.

You have a table of pointers to various routines residing at commandtable. Each command does something, updates Y and then goes back to the main loop again.

But each command takes time to execute. But when you use >20 clock cycles before the actual command code executes... it's not easy on the cpu. I suppose most commands I can think of would use under 50 clock cycles... but that's a long time for an interrupt IMHO.

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest