Jump to content
IGNORED

Trying to make some PoKEY music!


VinsCool

Recommended Posts

6 hours ago, emkay said:

Very nice. I'm missing the dying cats, which is a great thing :)

Good to know, that would mean my tuning is giving nice results.

I remember this tune sounded quite out of tune in the original rmt version, which I have uploaded on youtube sometime around 2019.

Link to comment
Share on other sites

Also made a dummy sa_c6502.dll

 

#include <stdint.h>
#include <stdio.h>

void __declspec(dllexport) C6502_Initialise(uint8_t *memory ) {
    fprintf(stderr, "%s: memory pointer set\n", __func__);
}

int __declspec(dllexport) C6502_JSR(uint16_t *adr,
                                    uint8_t *areg,
                                    uint8_t *xreg,
                                    uint8_t *yreg, int *maxcycles) {

    fprintf(stderr, "%s: PC=%04x A=%02x X=%02x Y=%02x maxcycles=%i\n",
            __func__, *adr, *areg, *xreg, *yreg, *maxcycles);
    return (*maxcycles)/2;
}

void __declspec(dllexport) C6502_About(char** name,
                                       char** author,
                                       char** description ) {
    *name        = "Dummy CPU";
    *author      = "Dummy";
    *description = "Doing nothing";
}

 

Output:

C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=3e00 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=3e00 A=00 X=01 Y=00 maxcycles=35568
C6502_JSR: PC=3e00 A=00 X=02 Y=00 maxcycles=35568
C6502_JSR: PC=3e00 A=00 X=03 Y=00 maxcycles=35568
C6502_JSR: PC=3e00 A=00 X=04 Y=00 maxcycles=35568
C6502_JSR: PC=3e00 A=00 X=05 Y=00 maxcycles=35568
C6502_JSR: PC=3e00 A=00 X=06 Y=00 maxcycles=35568
C6502_JSR: PC=3e00 A=00 X=07 Y=00 maxcycles=35568
C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568

Observations:

 

- No matter how many cycles you burn, C6502_JSR() is always called with maxcycles=35568

- 35568 is exactly 312*114, which is a PAL frame

- Even in NTSC mode, it uses the PAL amount of cycles :(

 

Result, combined with sa_pokey and apokeysnd:

 

PAL tunes are played at PAL clock speed?, audio is resampled with NTSC parameters.

NTSC tunes are played at PAL clock speed?, audio is resampled with NTSC parameters.

 

Neither seems correct, and PAL certainly isn't.

 

Edit: the value 35568 does not mean it is called 50 times per second insted of 60 in NTSC mode, but is does specify the maxcycles per PAL frame, which is larger than 262*114 for NTSC.

 

Edited by ivop
  • Like 2
  • Haha 1
Link to comment
Share on other sites

32 minutes ago, ivop said:

Also made a dummy sa_c6502.dll

 


#include <stdint.h>
#include <stdio.h>

void __declspec(dllexport) C6502_Initialise(uint8_t *memory ) {
    fprintf(stderr, "%s: memory pointer set\n", __func__);
}

int __declspec(dllexport) C6502_JSR(uint16_t *adr,
                                    uint8_t *areg,
                                    uint8_t *xreg,
                                    uint8_t *yreg, int *maxcycles) {

    fprintf(stderr, "%s: PC=%04x A=%02x X=%02x Y=%02x maxcycles=%i\n",
            __func__, *adr, *areg, *xreg, *yreg, *maxcycles);
    return (*maxcycles)/2;
}

void __declspec(dllexport) C6502_About(char** name,
                                       char** author,
                                       char** description ) {
    *name        = "Dummy CPU";
    *author      = "Dummy";
    *description = "Doing nothing";
}

 

Output:


C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=3e00 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=3e00 A=00 X=01 Y=00 maxcycles=35568
C6502_JSR: PC=3e00 A=00 X=02 Y=00 maxcycles=35568
C6502_JSR: PC=3e00 A=00 X=03 Y=00 maxcycles=35568
C6502_JSR: PC=3e00 A=00 X=04 Y=00 maxcycles=35568
C6502_JSR: PC=3e00 A=00 X=05 Y=00 maxcycles=35568
C6502_JSR: PC=3e00 A=00 X=06 Y=00 maxcycles=35568
C6502_JSR: PC=3e00 A=00 X=07 Y=00 maxcycles=35568
C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568

Observations:

 

- No matter how many cycles you burn, C6502_JSR() is always called with maxcycles=35568

- 35568 is exactly 312*114, which is a PAL frame

- Even in NTSC mode, it uses the PAL amount of cycles :(

 

Result, combined with sa_pokey and apokeysnd:

 

PAL tunes are played at PAL clock speed?, audio is resampled with NTSC parameters.

NTSC tunes are played at PAL clock speed?, audio is resampled with NTSC parameters.

 

Neither seems correct, and PAL certainly isn't.

 

Edit: the value 35568 does not mean it is called 50 times per second insted of 60 in NTSC mode, but is does specify the maxcycles per PAL frame, which is larger than 262*114 for NTSC.

 

this is also a problem in games, the pal programmer doesn't realize the extra frames are available for their code. the coder says it's out of cycles but it isn't... there is still more to go in the same time period but they need to use it and adjust accordingly. less code in each run of stitches, but more runs of stitches for 60. more code in each run of stitches, but less runs of stitches for 50. Both execute nearly the same amount of information in the same time period.

Edited by _The Doctor__
  • Like 2
Link to comment
Share on other sites

49 minutes ago, ivop said:

Observations:

 

- No matter how many cycles you burn, C6502_JSR() is always called with maxcycles=35568

- 35568 is exactly 312*114, which is a PAL frame

- Even in NTSC mode, it uses the PAL amount of cycles :(

 

Result, combined with sa_pokey and apokeysnd:

 

PAL tunes are played at PAL clock speed?, audio is resampled with NTSC parameters.

NTSC tunes are played at PAL clock speed?, audio is resampled with NTSC parameters.

 

Neither seems correct, and PAL certainly isn't.

 

Edit: the value 35568 does not mean it is called 50 times per second insted of 60 in NTSC mode, but is does specify the maxcycles per PAL frame, which is larger than 262*114 for NTSC.

 

LMFAO
Amazing findings!

So what I suspected from the beginning was indeed happening for real! hahahaha ?
That's indeed, a pretty cursed set of combinations, but I'm happy to know things still did work regardless!

I knew there was something this odd, things definitely were all PAL stuff with a strange flow going, and now I see you proved this was indeed true!
I suppose just like the CPU clock speed, there is a constant somewhere in the EXE that defines the cycles too?

At last, being able to adjust both would finally give the correct clock and pitch between regions, at the cost of having to edit the executable to then have 2 versions with the correct parameters?
I'm legitimately surprised something like this was overlooked, and never given any additional thought until you started doing that cool debugging stuff. ? 

  • Thanks 1
Link to comment
Share on other sites

The maxcycles calling variable is indeed a 32-bit LE constant in the binary, but decreasing that to 262*114 will not make any difference. The rmtplayr code will most likely always take way less cycles. Even if the pokey backend always resamples with NTSC parameters, it does matter how many times C6502_JSR() is called per second. I will check with a timer fprintf. Tomorrow. Not now ;)

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

15 minutes ago, ivop said:

The maxcycles calling variable is indeed a 32-bit LE constant in the binary, but decreasing that to 262*114 will not make any difference. The rmtplayr code will most likely always take way less cycles. Even if the pokey backend always resamples with NTSC parameters, it does matter how many times C6502_JSR() is called per second. I will check with a timer fprintf. Tomorrow. Not now ;)

That's probably right, I guess he just set the cycles per frame to PAL because it doesn't matter how many cycles are available as long as there are enough to run a full iteration of the RMT player. I guess it could be set to 100000000 cycles and make no difference (except perhaps slowing down your PC!)

  • Like 1
Link to comment
Share on other sites

35 minutes ago, rensoup said:

That's probably right, I guess he just set the cycles per frame to PAL because it doesn't matter how many cycles are available as long as there are enough to run a full iteration of the RMT player. I guess it could be set to 100000000 cycles and make no difference (except perhaps slowing down your PC!)

No, it always stops at the last rts :) which is way before the maxcycles value. Even sooner than maxcycles/4 ;)

  • Like 2
Link to comment
Share on other sites

Okay, I couldn't resist. Here's a timer sa_c6502.c

 

#include <stdint.h>
#include <stdio.h>
#include <sys/time.h>

int prev = 0;

void __declspec(dllexport) C6502_Initialise(uint8_t *memory ) {
    fprintf(stderr, "%s: memory pointer set\n", __func__);
}

int __declspec(dllexport) C6502_JSR(uint16_t *adr,
                                    uint8_t *areg,
                                    uint8_t *xreg,
                                    uint8_t *yreg, int *maxcycles) {

    struct timeval  tv;
    gettimeofday(&tv, NULL);

    fprintf(stderr, "%s: PC=%04x A=%02x X=%02x Y=%02x maxcycles=%i\n",
            __func__, *adr, *areg, *xreg, *yreg, *maxcycles);

    fprintf(stderr, "%s: ms=%u\n", __func__, (tv.tv_usec - prev)/1000);

    prev = tv.tv_usec;
    return (*maxcycles)/2;
}

void __declspec(dllexport) C6502_About(char** name,
                                       char** author,
                                       char** description ) {
    *name        = "Dummy CPU";
    *author      = "Dummy";
    *description = "Doing nothing";
}

It's very crude, my rounding is off, but it does the job. I needed to copy /usr/lib/gcc/i686-w64-mingw32/8.3-win32/libgcc_s_sjlj-1.dll  to my local wine rmt test directory at ~/.wine-rmt-test/drive_c/rmt/. to get gettimeofday() to work.

 

PAL:

C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: ms=20
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: ms=0
C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: ms=19
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: ms=0
C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: ms=20
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: ms=0
C6502_JSR: PC=3e00 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: ms=19

NTSC:

C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: ms=16
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: ms=0
C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: ms=17
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: ms=0
C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: ms=16
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: ms=0
C6502_JSR: PC=3406 A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: ms=17
C6502_JSR: PC=340c A=00 X=00 Y=00 maxcycles=35568
C6502_JSR: ms=0

As I said, very crude, but it's clear enough that the CPU emulation is called at circa 16.6 ms intervals for NTSC and at circa 20ms intervals for PAL, which seems OK.

 

Edited by ivop
  • Like 1
  • Thanks 1
Link to comment
Share on other sites

1 hour ago, ivop said:

No, it always stops at the last rts :) which is way before the maxcycles value. Even sooner than maxcycles/4 ;)

No as in it will not slow down your PC ?

 

Of course if it terminates with a RTS (instead of using some form of sync method which is unnecessary here) but your previous message seemed to imply it was a bug to call the 6502 emu with the same number of cycles for PAL & NTSC:

 

5 hours ago, ivop said:

- No matter how many cycles you burn, C6502_JSR() is always called with maxcycles=35568

- 35568 is exactly 312*114, which is a PAL frame

- Even in NTSC mode, it uses the PAL amount of cycles :(

 

...But we're agreeing that it's irrelevant I think ?

 

this one at least should be fine:

5 hours ago, ivop said:

NTSC tunes are played at PAL clock speed?, audio is resampled with NTSC parameters.

?

  • Like 1
Link to comment
Share on other sites

57 minutes ago, rensoup said:

No as in it will not slow down your PC ?

Yes, it will not slow down your PC, as the emulation stops if the init or play routine ends with an RTS.

Quote

Of course if it terminates with a RTS (instead of using some form of sync method which is unnecessary here) but your previous message seemed to imply it was a bug to call the 6502 emu with the same number of cycles for PAL & NTSC:

...But we're agreeing that it's irrelevant I think ?

Yes, we agree. The maxcycles value is irrelevant in regard to the eventual playback speed.

Quote

this one at least should be fine:

[NTSC tunes with NTSC resampling]

?

Yes, I think so. My latest experiment shows that the 6502 player is indeed called circa 60 times per second in NTSC mode, and its writes to Pokey registers are sampled at least at that rate, and then the final audio signal is resampled with NTSC clock speed resampling parameters, so that should be fine. Sort of ;)

 

Edit: BTW it's not entirely clear yet how apokeysnd resamples. Previous remarks are all about sa_pokey. apokeysnd doesn't set its CPU clock speed in any way, but I have not yet checked which is the default it uses. It will be wrong for either NTSC or PAL, depending on which resampling it uses.

Edited by ivop
typoo
  • Like 1
  • Thanks 1
Link to comment
Share on other sites

I have something I guess.

 Not really a finished thing so I can always edit it again another day.
I was actually going to work on something different, but was not feeling it and started to sketch random patterns, and this was the result after a few hours tonight lol

 

sketch 58.obx

  • Like 5
Link to comment
Share on other sites

I forgot to post this one yesterday for some reason, so here's some grating sounds with some bass and drums.
Another messy project I started pretty much.

No visual player because I did not bother, and no LZSS since my RMT code is handling 16-bit in a totally different way.
 

 

Sketch 59 v1.xex

  • Like 4
Link to comment
Share on other sites

Major improvements with both the visual player project and the rmtplayr that is tightly bonded to it!

Spring - Phasebass + rmtplayr 15khz New Hijack Test

Now 100% AUDCTL based, that makes switching between modes absolutely painless.
Not shown on this one, my new 16-bit code took the same approach and works just as well.

The rmtplayr code should work in the actual tracker, in theory.
I have yet to try making it fit, after I'm done optimising what I did change and add.

Also showcased: major improvements in the visual player code, cleaned up a lot of the graphic routines, fixed many nasty bugs I did not even know were there until I started to get accurate informations displayed on screen (still unfinished, so there may be some incorrect things here and there).
I've been learning 6502 ASM slowly over the last month, but surely, things are going somewhere.

Original module by Spring. 

Phasebass.obx

  • Like 7
Link to comment
Share on other sites

My next major RMT hack version is getting pretty good now.
I can confirm pretty much all of the new code I introduced and compacted as much as possible to fit within the limits of the binary size held into the .exe
Stereo support isn't yet done but that shouldn't take very long to adjust.


So now all the 15khz tuning for Distortion A and C is handled automatically based on the global v_audctl variable, no extra tracking work required.
As long as something has the correct AUDCTL bit, effects will be for all the channels regardless of the instrument used.

I also made an interesting observation.
I found out the trackn_outnote variables may be hardcoded specifically for the tracker side too.
I literally don't use them at all in my new code, nor are they called anywhere since I removed the BASS16 code entirely.
But for some obscure reason, the simple fact of commenting out the code and initialisation in memory is enough to break the tracker side!
It baffled me since I could already confirm all my code worked perfectly fine in SAP and XEX exports, and the visual player project has been using the same code for some time too.
I simply worked around it for now with a global define, so when FEAT_IS_TRACKER is 1, the extra code is also assembled.
The unused code wasted around 8 bytes, something I really was not able to afford for the MONO player, but I worked around it :P 
So I guess I can now confirm there are indeed 3 different binaries in the program: PLAYER, MONO then STEREO, and so far they all work with that workaround.

So anyway here's a test tune I made during the day, it doesn't look like much, but the automatic handling of 16-bit, and 15khz, really makes the workflow infinitely more comfortable.
This is still being tested and edited, since the stereo support is incomplete, but as far as my testing goes, pretty much everything appears to work correctly :D 

 

PAL 50hz

Sketch 60 v2.xex

  • Like 6
Link to comment
Share on other sites

Ok that was a lot more frustrating than anticipated but I finally got my 'clear volume bars' code fully working!

At the bottom of the screen, the lighter blue colour (used there for the clear screen stuff) was so heavy before it used to fill the entire VBI area, and even leak at the top of the screen during the next frame!
Next step is naturally the "high pass filter, Join (16-bit and Two-Tone) tiles, using much of a similar approach.

 


Not shown there yet but I've been busy rewriting the entire graphic code since Monday, it's finally paying off!
I'm getting much better performances and less bloated code, as I still learn how all this stuff works, I can finally get it do what I want :D 
The VBI time wobbles less and less at the top of the screen, and I may be able to improve things a lot more since there are many things that need to be redone.
At this point I've changed the code so much it's hardly the same it was when I started poking at it now :) 

So what I am doing now is rewrite a lot of the routines, and make it so it only draws (or clear) portions of the screen when it is actually necessary.
So far I got most of the 'drawn' stuff optimised pretty loosely, and that was quite a massive improvement already, so there's good amount of hope for even better :P 

  • Like 2
Link to comment
Share on other sites

33 minutes ago, _The Doctor__ said:

can you load the player with one of your other recent sketches so we can compare? this generic does not sound like your other generic

Sure I can load a bunch and drop a bunch of binaries in here later if you want.
They will pretty much all play back very nicely now, on par to the RMT Patch version since they use the exact same code.

 

The only player that will perform a lot better is the LZSS converter, however :D 

  • Like 1
Link to comment
Share on other sites

  • 3 weeks later...

Wow been a while since I posted in this thread.

Here's a WIP of a cover I am working on using many of the recent RMT patch features I was able to get working.

Having a total control over the AUDCTL with Command 7 simulating an envelope, it becomes seriously powerful in good hands.

Also not so obvious but the .obx is actually my recreation of the .xex export format player, with some of my own changes to make it easier to edit, but overall should behave almost exactly the same :P 

This also uses some of the code from the more graphically appealing Visualizer, but this one isn't yet ready to be released :D 

 

The tune is currently incomplete but it's on a good start, I thought it was worth sharing since I haven't made much tunes in a while, being mostly busy with either life or learning how to code in 6502 ASM, haha

Personal Jesus WIP.obx

  • Like 6
Link to comment
Share on other sites

7 hours ago, VinsCool said:

Wow been a while since I posted in this thread.

Here's a WIP of a cover I am working on using many of the recent RMT patch features I was able to get working.

Having a total control over the AUDCTL with Command 7 simulating an envelope, it becomes seriously powerful in good hands.

Also not so obvious but the .obx is actually my recreation of the .xex export format player, with some of my own changes to make it easier to edit, but overall should behave almost exactly the same :P 

This also uses some of the code from the more graphically appealing Visualizer, but this one isn't yet ready to be released :D 

 

The tune is currently incomplete but it's on a good start, I thought it was worth sharing since I haven't made much tunes in a while, being mostly busy with either life or learning how to code in 6502 ASM, haha

Personal Jesus WIP.obx 8.22 kB · 1 download

That's great - will definitely want to hear the final version of this.

  • Like 2
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...