Page 1 of 1

AY Crudentials: 4 Bit Samples

Posted: Sun Jan 22, 2006 11:36 am
by Twilighte
The process of Playing a 4 Bit sample is alot easier than an 8 or 2 bit since this is what the AY-3-8912 can handle. The problem is in deciding the format of the source byte.
The Source byte is 8 bits, which may potentially store two 4 bit sample values.
Their are 4 formats possible.
Format 1: 4BIT
Simply storing the 4 bits in the 8 bits available.
However, this is just plain inefficient.

Format 2: B0B1
Keeping to Format 1 but the top 4 bits store a second sample, which may potentially be an extension of the first sample once the lower 4 bit sample has finished.
Note: SoundTracker used this format, but assigned the lower 4 bits to Bank 0 and the upper to Bank 1 (Hence the name BOB1).
Format 3: LOHI
the lower 4 bits is the first value of the byte and the higher 4 bits is the second.
Format 4: HILO
the higher 4 bits is the first value of the byte and the lower 4 bits is the second.

The other problem is detecting the end of a sample.
In my experience, i have used 3 different formats over the years for detecting the end.
Format 1: ZERO (ZERO in data is end)
one value of the 4 bit entity is used to trigger an end, that value being 0.
This is by far the simplest method but does reduce the available values to 1 to 15.
Format 2: HEND (High marks END)
All samples are trimmed to a 256 boundary and always start from the same 256 boundary, then only the high byte of the location needs to be checked for the end location.
Format 3: LEND (Location is END)
A samples end is detected by both Low and High byte End Detection. This has the diasadvantage of being slow (in the play routine) to detect but the advantage of being memory efficient.

The final problem is deciding how the machine code routine plays the sample. A sample must be played at an even tempo otherwise it will sound wrong because the speed will differ from the original the sample was taken from.
The are two known methods for accomplishing this.
Method 1: Play using Cycle exact routine
The sample routine is written accounting for every cycle in the actual code.
Each machine code instruction takes an exact number of machine cycles to execute. With this knowledge it is possible to both calculate the speed of operation and that every loop will consume the same number of cycles.
SoundTracker used this method
Method 2: Play on Interrupt
The sample play routine is placed inside an interrupt framework, which leaves the actual precise timing to the Timer used for the interrupt.
Sonix 4.00 used this method

Posted: Sun Jan 22, 2006 5:38 pm
by Dbug
In the VIP4 demo we are using if I remember correctly 4 bit samples (two of them in each byte), replayed with a fast interupt routine.

There are actually two routines, one knows how to extract low nibble, and the other one the high nibble. Each one change the IRQ handler to point on the other one, thus removing tests in the code. This makes it very fast.

Of course changing the IRQ adress itself takes time, but we solved the problem by just using INC and DEC on the high byte of the adress:

Code: Select all

   IrqPtr=IRQ1

; allign on 256 bytes bounday
IRQ1:
   ; do some work
   INC IrqPtr
   ; return

; allign on 256 bytes bounday
IRQ2:
   ; do some work
   DEC IrqPtr
   ; return
   
I don't know if it possible to do any faster on the 6502 ?

Posted: Mon Jan 23, 2006 12:07 pm
by Euphoric
Of course changing the IRQ adress itself takes time, but we solved the problem by just using INC and DEC on the high byte of the adress
Very clever !!
I can't see a faster way, except without using interrupts of course...

Posted: Wed Feb 15, 2006 12:15 am
by Twilighte
I don't know if it possible to do any faster on the 6502 ?
Yes i believe it is...
As part of the Digidrum and SID solution for a new Tracker i am designing, i have worked out that by putting the Low byte routine in Zero page and the high byte routine at the beginning of Page 1, we should save a few cycles. The advantage of this is that now i get to increment the digidrum (Sample) address in zero page which saves on a few cycles.
Some other parts of the code are also sped up, especially where i temporarily store a value to be picked up later in the code. I simply use an LDA #00 instead of the LDA temp_variable and i save at least 1 more cycle.
AFAIK, with 64 bytes used at the start of page 1 i would have to jsr to a depth of 64 levels before i started to see corruption of the code in page 1?

Posted: Sun Jul 31, 2011 4:34 pm
by Dbug
Good thing I started to re-read all these old audio threads; I'm starting to work again on making an efficient generic 4 bit sample replay package and I totally forgot about putting the whole routine in zero page :)

Posted: Sun Jul 31, 2011 8:14 pm
by Symoon
Dbug, if you ever need it, I had worked on Manoir de Mortevielle phonems samples to fit in the Oric memory, to play them with Twilighte's routines. Don't recall what I did exactly at the time but if you ever are interested in part of this work, let me know.

Posted: Sun Jul 31, 2011 9:47 pm
by Dbug
That could be a nice way to make a speaking adventure game :)

Posted: Sat Aug 06, 2011 9:00 pm
by highwayman
use 4bits for the sample and the other 4 bits or some of them for the duration.

it acts as a crude compression method, but as your only using 4bit audio there will probably be noticable savings by doing it because you will probably see regular multiples of the same nibble..

my home-made logic analyser uses a similar trick to save on memory.