fastest way to play ym music on ST

All 680x0 related coding posts in this section please.

Moderators: simonsunnyboy, Mug UK, Zorro 2, Moderator Team

User avatar
Nyh
Atari God
Atari God
Posts: 1496
Joined: Tue Oct 12, 2004 2:25 pm
Location: Netherlands

Postby Nyh » Fri Nov 26, 2004 11:57 am

Gunstick wrote:I think you did not get the reason for this thread. We discuss how we can create a space efficient but still fast playable music format.


I know. How much space do you want to trade for more speed? Or how much speed do you want to trade for smaller data? I usually go for first max speed.

p01 wrote:That way, the SOS tune ( an example picked completely at random Wink ) takes 27,708 bytes instead of 29,809 bytes if the bitfield of all the registers is always stored.


If you are coding for such random tunes as the SOS tune you better first have a look at the data:

Code: Select all

reg update count
 2   4816
 9   2980
 3   2573
 7   1715
 4   1230
10   1102
 0    873
 1    807
 6    177
11    143
 5     67
13      0
12      0
 8      0

Registers 8, 12, 13 are not updated so no need to write code for it. Reoder the registers on occurence. You might consider to couple updates to registers 0 and 1 (they both are the frequency of channel A) then you can pack the most frequent registers into 7 bits and only need an extension byte 387 times at max. (Updating registers 0 and 1 as an pair costs 66 bytes extra but saves at least (807-387)=420 extension bytes.)

Warning: I didn't check whether the data I analysed was indeed SOS by Mad Max. I just grabbed the music data in the source directory from a screen that should contain SOS as music. But who knows what happened to that directory the last 12 years?

Nyh

User avatar
p01
Captain Atari
Captain Atari
Posts: 158
Joined: Mon Nov 22, 2004 1:27 am
Location: Oslo, Norway
Contact:

Postby p01 » Fri Nov 26, 2004 12:11 pm

:P I tried to make my routine rather general, but for the sprite record thing, every nop and byte saved are welcome. Thank you for pointing the re-arrangement by number of updates.

[edit] with this improvement the SOS tunes takes 24,794 bytes [/edit]
Last edited by p01 on Fri Nov 26, 2004 1:42 pm, edited 1 time in total.

User avatar
megar
Atari maniac
Atari maniac
Posts: 85
Joined: Mon Nov 22, 2004 8:33 am
Location: East of France
Contact:

indeed

Postby megar » Fri Nov 26, 2004 1:07 pm

I've already picked up that. (registry 8, 12 and 13 not used). I was planning to use this trick in my soon-to-be-released sprite record contest attempt.

But, 3 to 4 nop by vbl, it is not so important anyway, so I think that most code that have be published here is appliable.

Gunstick
Captain Atari
Captain Atari
Posts: 262
Joined: Thu Jun 20, 2002 6:49 pm
Location: Luxembourg
Contact:

Re: indeed

Postby Gunstick » Fri Nov 26, 2004 7:04 pm

megar wrote:I've already picked up that. (registry 8, 12 and 13 not used). I was planning to use this trick in my soon-to-be-released sprite record contest attempt.

But, 3 to 4 nop by vbl, it is not so important anyway, so I think that most code that have be published here is appliable.


I'm not shure that 12 and 13 are not used because the SOS tune is using the envolope quite heavily, it's at least once used for initialization.
Make shure your playerroutine is actually working correctly and compare the tune with the original. E.g. some of the released sprite demos don't use the envelope and just sound wrong.

My aim is to create an interchangeable and standard fileformat. The idea of reordered registers by usage is good, but perhaps a little overkill.
It would be nice if Nyh could check out some other songs for register usage.

I guess that the following grouping would be useful:
Use 1 bit for each of the frequency registers (3bits) then register 7,8,9,10 (4 bits) and last register 6 (noise frequency). Noise is 5 bit, so the 3 top bits can be used for next values: envelope frequency (regs 11,12) 1 bit and envelope type 1bit. Then we have 1 bit left. If it's set to 1, we come to the "extra features" like SID, digits or end-of-song.

e.g:

Code: Select all

01100011     ; freq channel B and C, volume C and noise
bbbbbbbb     ; channel B freq
0000bbbb
ccccccccc     ; channel C freq
0000cccc
0000cccc     ; volume C
100nnnnn   ; noise and continue: 100 = envelope freq, no reg 13, end
eeeeeeee       ; envelop frequency
eeeeeeee
..... (next VBL)


Now that I think of it, the frequency registers are 12 bit, so we can use already there the noisefreq "extension".

So another idea is not to use at all a bit-field, but store that info with the data. Each VBL we read a byte, if none of the top 3 bits is set, there is no frequency register to be modified.
If a bit is set (7,6 or 5), we store the data into register 1,3 or 5 and then copy the next byte into 0,2 or 4 respectively.
If there's another bit set (6 or 5) do the same again.
This means if frequency A and C has to be modified, the first byte will have top bits like 101. If it's B and C it will be 011 etc...

And finally if bit 4 is set, there's more data, else we have finished.

Code: Select all

0111bbbb   ; regs b&c and more...
bbbbbbbb   ; channel B freq
0000cccc    ; channel C freq
cccccccc
00100100  ; volumes ABC, reg6, reg7, envfreq, reg13, 'more'
0000cccc   ; volume C
eeeeeeee    ; envelope freq
eeeeeeee
.... (next VBL)


So: play nothing is just $00
Modify something but not frequency is %00010000

Discussion open: shall we continue on this way? I mean, is there someone coming up with a fast routine to decode this?
Or other crazy suggestions?

Georges

User avatar
p01
Captain Atari
Captain Atari
Posts: 158
Joined: Mon Nov 22, 2004 1:27 am
Location: Oslo, Norway
Contact:

Postby p01 » Fri Nov 26, 2004 7:46 pm

For the informations, the number of updates per register in the SOS tune ( which counts 6150 frames ) are:

Code: Select all

    [2] => 5442
    [9] => 2994
    [3] => 2575
    [7] => 1717
    [4] => 1232
    [10] => 1216
    [0] => 1003
    [1] => 937
    [6] => 178
    [11] => 144
    [5] => 68
    [13] => 1
    [8] => 1
    [12] => 1
/!\ the registers are set at least one time, thus the 1s for the registers #13, #8 and #12.

My routine with the tune shrinked to 24,794 bytes replays the tune correctly. And as you can from the occurence of updates, the second part of my player is only executed 937 times among the 6150 frames ofthe tune.

As for making a standard player routine, it's possible to put the order of the registers in an header and auto-modify the player routine during the init process.

User avatar
Nyh
Atari God
Atari God
Posts: 1496
Joined: Tue Oct 12, 2004 2:25 pm
Location: Netherlands

Re: indeed

Postby Nyh » Sat Nov 27, 2004 2:44 am

Gunstick wrote:It would be nice if Nyh could check out some other songs for register usage.


All coders are lazy. My sample routines just sample all 14 registers during songplay. Makes register counting a lot easier.

Code: Select all

/*
 * analyse regsiter gebruik songs
 * 14 registers worden gebruikt
 * hoevaak worden ze geupdated?
 */

#include <stdio.h>

#define BUFFER (1024UL*1024UL)

typedef unsigned int word;
typedef unsigned char byte;

byte music[BUFFER];

int main(void)
{
  long size=0;
  {
    FILE* f;
    if((f=fopen("SOS.dat","rb"))==NULL)
    {
      printf("File open error!\n");
      return -1;
    }
    size=fread(music, 1, BUFFER, f);
    fclose(f);
  }
  printf("size = %li\n", size);
  {
    long count[14]={0};
    long updates=size/14;
    long i;
    byte* p=music+14;
    for(i=1;i<updates;i++)
    {
      int j;
      for(j=0;j<14;j++)
      {
        if(*p!=p[-14])
        {
          count[j]++;
        }
        p++;
      }
    }
    {
      int j;
      for(j=0;j<14;j++)
      {
        printf("Register %2i = %li maal\n", j, count[j]);
      }
    }
  }
  return 0;
}


Nyh

User avatar
Nyh
Atari God
Atari God
Posts: 1496
Joined: Tue Oct 12, 2004 2:25 pm
Location: Netherlands

Postby Nyh » Sat Nov 27, 2004 2:45 am

p01 wrote:the registers are set at least one time, thus the 1s for the registers #13, #8 and #12.


Of course all registers are set one time. But if registers after initialisation do not change don't write code for it to change if you are in a hurry. Still think you should combine register 0 and 1 into a pair. Saves you a lot of bytes.

Nyh

Gunstick
Captain Atari
Captain Atari
Posts: 262
Joined: Thu Jun 20, 2002 6:49 pm
Location: Luxembourg
Contact:

Postby Gunstick » Sat Nov 27, 2004 8:26 am

it's not exactly that easy, but for the SOS tune it's working.

LUCKY!

And the problem is the register 13. If writing the same value as before into 13, this causes an effect (restart of wave). You can notice that if you play the SOS tune with the full 13 registers or just with 12 and with an initvalue for r13 at the beginning.

That's why my save routine is now like this (this writes some sort of my YMX format):

Code: Select all

         move.l musicsave,a0
         lea ymregisters,a1
         moveq #0,d2   ; which regs change
         move.l a0,a2  ;save curr pointer for writing bitfield
          addq.l #1,a0
         ; special r13 treatment
         move.b #13,$ffff8800.w
         move.b $ffff8800.w,d1
         cmp.b #%0011,d1      ; no 'ULM' value, then it's gotten written to
         beq.s ymr13notmod
         or.b #%1,d2
         move.b d1,(a0)+  ;write r13
ymr13notmod:
         moveq #12,d3   ; remaining regs r0-r12
          moveq #6,d4   ; remaining regs r6-r12
ym_readloop:
          add.b d2,d2  ; shift left
         move.b d3,$ffff8800.w
         move.b $ffff8800.w,d1
         cmp.b (a1,d3),d1
         beq.s ymnotmod   ; modified
         or.b #%1,d2      ; set bit if mod
         move.b d1,(a0)+  ; only write this reg
        add.w   d3,d3
        add.w #1,-26(a1,d3)
        lsr.w #1,d3
ymnotmod:
         move.b d1,(a1,d3)
         subq #1,d3
          dbra d4,ym_readloop
          move.b d2,(a2)   ; save bitfield, bit7=reg13, bit0=reg6
          moveq #0,d2   ; which regs change
          move.l a0,a2  ;save curr pointer for writing bitfield
          addq.l #1,a0
          moveq #5,d3   ; remaining regs r5-r0
ym_readloop2:
          add.b d2,d2  ; shift left
          move.b d3,$ffff8800.w
          move.b $ffff8800.w,d1
          cmp.b (a1,d3),d1
          beq.s ymnotmod2   ; modified
          or.w #%100,d2      ; set bit if mod
          move.b d1,(a0)+  ; only write this reg
        add.w   d3,d3
        add.w #1,-26(a1,d3)
        lsr.w #1,d3
ymnotmod2:
          move.b d1,(a1,d3)
          dbra d3,ym_readloop2
          move.b d2,(a2)   ; save bitfield, bit7=reg5, bit2=reg0
         move.l a0,musicsave
        move.b #13,$ffff8800.w      ; init r13 with
        move.b #%0011,$ffff8802.w   ; unusual 'ULM' value

       jsr music+8


The trick is to write a silly value into r13 (0011 means hold & alternate, which is very probably never used) and test in the next vbl if it's still there.
The music sounds awful then, but the sampling is correct.

George

gwEm
Captain Atari
Captain Atari
Posts: 220
Joined: Tue Jun 08, 2004 4:43 pm
Location: London, UK
Contact:

Postby gwEm » Thu Dec 02, 2004 11:02 am

heres the source for hubbard's driver:

http://www.kubarth.de/sid/index.html

of course its SID on C64, so not totally relevant. but some very interesting principals - fast and a very space effective file format.

i was astonished by its simplicity.

User avatar
Grazey / PHF
Captain Atari
Captain Atari
Posts: 497
Joined: Fri Jun 21, 2002 12:50 pm
Location: Montreal, Quebec
Contact:

Postby Grazey / PHF » Thu Dec 02, 2004 11:37 am

Oooh the Hubbard driver!

A nice way to waste 15 mins at work... I am reading it now. :D

Gwem: started the cold project.... maybe done tonight..

Grz
http://phf.atari.org - demo coders since 1983
http://sndh.atari.org - Maintainer of the Atari ST chip music archive
http://www.scenemusic.net - Nectarine Administrator

User avatar
simonsunnyboy
Moderator
Moderator
Posts: 5116
Joined: Wed Oct 23, 2002 4:36 pm
Location: Friedrichshafen, Germany
Contact:

Postby simonsunnyboy » Thu Dec 02, 2004 12:41 pm

Very interesting read - even for those like me who have hardly any knowledge about music. At least it gives a good sketch how playback should work regardless of CPU and synth chip used!
Simon Sunnyboy/Paradize - http://paradize.atari.org/

Stay cool, stay Atari!

1x2600jr, 1x1040STFm, 1x1040STE 4MB+TOS2.06+SatanDisk, 1xF030 14MB+FPU+NetUS-Bee

User avatar
Mug UK
Administrator
Administrator
Posts: 11401
Joined: Thu Apr 29, 2004 7:16 pm
Location: Stockport (UK)
Contact:

Postby Mug UK » Thu Dec 02, 2004 3:45 pm

This brings to light a conversation a few moons ago with "ADM" who wrote the Mad Max Music Editor Demo.

He was planning on implementing the ability to import JCH songs direct from the C64 .. now *that* would have been fantastic function if he'd ever got that far.
My main site: http://www.mug-uk.co.uk - slowly digging up the bits from my past (and re-working a few): Atari ST, Sega 8-bit (game hacks) and NDS (Music ripping guide).

I develop a free Word (for Windows) add-in that's available for Word 2007 upwards. It's a fix-it toolbox that will allow power Word users to fix document errors. You can find it at: http://www.mikestoolbox.co.uk


Social Media

     

Return to “680x0”

Who is online

Users browsing this forum: No registered users and 1 guest